WIP: [android] Add Speed class #7955

Draft
gpesquero wants to merge 1 commit from gpesquero/speed_class into master
7 changed files with 236 additions and 4 deletions

View file

@ -1953,4 +1953,10 @@ Java_app_organicmaps_Framework_nativeGetKayakHotelLink(JNIEnv * env, jclass, jst
return url.empty() ? nullptr : jni::ToJavaString(env, url);
}
JNIEXPORT jint JNICALL
Java_app_organicmaps_Framework_nativeGetUnits(JNIEnv *, jclass)
{
return static_cast<jint>(measurement_utils::GetMeasurementUnits());
}
} // extern "C"

View file

@ -57,6 +57,14 @@ JNIEXPORT jobject JNICALL Java_app_organicmaps_util_StringUtils_nativeFormatSpee
platform::GetLocalizedSpeedUnits(units));
}
JNIEXPORT jobject JNICALL Java_app_organicmaps_util_StringUtils_nativeStringFormatSpeedAndUnits(
JNIEnv * env, jclass thiz, jdouble metersPerSecond)
{
auto const units = measurement_utils::GetMeasurementUnits();
return jni::ToJavaString(env, measurement_utils::FormatSpeedNumeric(metersPerSecond, units) +
";" + platform::GetLocalizedSpeedUnits(units));
}
JNIEXPORT jobject JNICALL
Java_app_organicmaps_util_StringUtils_nativeFormatDistance(JNIEnv * env, jclass, jdouble distanceInMeters)
{

View file

@ -60,6 +60,10 @@ public class Framework
public static final int ROUTER_TYPE_TRANSIT = 3;
public static final int ROUTER_TYPE_RULER = 4;
// Units values shall be the same as the ones defined in c++ in <platform/measurement_utils.hpp>.
public static final int UNITS_METRIC = 0;
public static final int UNITS_IMPERIAL = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ROUTE_REBUILD_AFTER_POINTS_LOADING})
public @interface RouteRecommendationType {}
@ -460,4 +464,6 @@ public class Framework
@Nullable
public static native String nativeGetKayakHotelLink(@NonNull String countryIsoCode, @NonNull String uri,
long firstDaySec, long lastDaySec, boolean isReferral);
public static native int nativeGetUnits();
}

View file

@ -155,7 +155,7 @@ public class NavigationController implements TrafficManager.TrafficCallback,
updateVehicle(info);
updateStreetView(info);
mNavMenu.update(info);
mNavMenu.update(info, Framework.nativeGetUnits());
}
private void updateStreetView(@NonNull RoutingInfo info)

View file

@ -0,0 +1,171 @@
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
package app.organicmaps.util;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import android.content.Context;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import android.util.Pair;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import java.text.DecimalFormat;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import java.text.DecimalFormatSymbols;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import java.text.NumberFormat;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import java.util.Formatter;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import java.util.Locale;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import app.organicmaps.Framework;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
import app.organicmaps.util.log.Logger;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
public class Speed
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private static String mUnitStringKmh = "km/h";
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private static String mUnitStringMiph = "mph";
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private static char mDecimalSeparator = Character.MIN_VALUE;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
public static double MpsToKmph(double mps) { return mps * 3.6; }
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
public static double MpsToMiph(double mps) { return mps * 2.236936; }
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
public static void setUnitStringKmh(String unitStringKmh) { mUnitStringKmh = unitStringKmh; }
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
public static void setUnitStringMiph(String unitStringMiph) { mUnitStringMiph = unitStringMiph; }
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private final static DecimalFormat mDecimalFormatNoDecimal = new DecimalFormat("#");
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private final static DecimalFormat mDecimalFormatOneDecimal = new DecimalFormat("0.0");
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private final static Locale mLocale = Locale.getDefault();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private final static StringBuilder mSb = new StringBuilder();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private final static Formatter mFormatter = new Formatter(mSb, mLocale);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private final static NumberFormat mNumberFormatNoDecimal = NumberFormat.getInstance(mLocale);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
private final static NumberFormat mNumberFormatOneDecimal = NumberFormat.getInstance(mLocale);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
public static Pair<String, String> formatMeasurements(double speedInMetersPerSecond, int units,
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Context context)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
double speedValue;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
String unitsString;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (units == Framework.UNITS_IMPERIAL)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedValue = MpsToMiph(speedInMetersPerSecond);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
unitsString = mUnitStringMiph;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
else
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedValue = MpsToKmph(speedInMetersPerSecond);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
unitsString = mUnitStringKmh;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
// Option 1: String.format()
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long start1 = System.nanoTime();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
String formatString = (speedValue < 10.0)? "%.1f" : "%.0f";
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:30 +00:00 (Migrated from github.com)
Review

Can this string be pre-cached?

Can this string be pre-cached?
String speedString = String.format(mLocale, formatString, speedValue);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long elapsed1 = System.nanoTime() - start1;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Logger.i("LOCALE_MEASURE", "1) " + speedString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
// Option 2: DecimalFormat class
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long start2 = System.nanoTime();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (speedValue < 10.0)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = mDecimalFormatOneDecimal.format(speedValue);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
else
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = mDecimalFormatNoDecimal.format(speedValue);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long elapsed2 = System.nanoTime() - start2;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Logger.i("LOCALE_MEASURE", "2) " + speedString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
// Option 3: Long.toString() + StringBuffer.insert()
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long start3 = System.nanoTime();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (speedValue < 10.0)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = Long.toString(Math.round(speedValue * 10.0));
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
StringBuffer buffer = new StringBuffer(speedString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (mDecimalSeparator == Character.MIN_VALUE)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
mDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
// For low values (< 1.0), force to have 2 characters in string.
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (buffer.length() < 2)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
buffer.insert(0, "0");
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
buffer.insert(1, mDecimalSeparator);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = buffer.toString();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
else
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = Long.toString(Math.round(speedValue));
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long elapsed3 = System.nanoTime() - start3;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Logger.i("LOCALE_MEASURE", "3) " + speedString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
// Option 4: Formatter class
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
mSb.setLength(0);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long start4 = System.nanoTime();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (speedValue < 10.0)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
mFormatter.format("%.1f", speedValue);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
else
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
mFormatter.format("%d", Math.round(speedValue));
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = mSb.toString();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long elapsed4 = System.nanoTime() - start4;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Logger.i("LOCALE_MEASURE", "4) " + speedString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
// Option 5: NumberFormat class
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
mNumberFormatNoDecimal.setMaximumFractionDigits(0);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
mNumberFormatOneDecimal.setMaximumFractionDigits(1);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long start5 = System.nanoTime();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (speedValue < 10.0)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = mNumberFormatOneDecimal.format(speedValue);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
else
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = mNumberFormatNoDecimal.format(Math.round(speedValue));
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
long elapsed5 = System.nanoTime() - start5;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Logger.i("LOCALE_MEASURE", "5) " + speedString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
String text = String.format(Locale.US,
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
"Java calls: %5d / %5d / %5d / %5d / %5d",
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Math.round(0.001 * elapsed1),
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Math.round(0.001 * elapsed2),
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Math.round(0.001 * elapsed3),
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Math.round(0.001 * elapsed4),
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Math.round(0.001 * elapsed5));
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Logger.i("LOCALE_MEASURE", text);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
return new Pair<>(speedString, unitsString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
public static Pair<String, String> format(double speedInMetersPerSecond, int units,
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
Context context)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
double speedValue;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
String unitsString;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (units == Framework.UNITS_IMPERIAL)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedValue = MpsToMiph(speedInMetersPerSecond);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
unitsString = mUnitStringMiph;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
else
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedValue = MpsToKmph(speedInMetersPerSecond);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
unitsString = mUnitStringKmh;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
String speedString;
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (speedValue < 10.0)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
{
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = Long.toString(Math.round(speedValue * 10.0));
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
StringBuffer buffer = new StringBuffer(speedString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (mDecimalSeparator == Character.MIN_VALUE)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
mDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
// For low values (< 1.0), force to have 2 characters in string.
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
if (buffer.length() < 2)
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
buffer.insert(0, "0");
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
buffer.insert(1, mDecimalSeparator);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = buffer.toString();
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
else
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
speedString = Long.toString(Math.round(speedValue));
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
return new Pair<>(speedString, unitsString);
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )
}
biodranik commented 2024-04-19 07:39:01 +00:00 (Migrated from github.com)
Review

What if these strings will be loaded once (avoid calling context.getString on each call)?

What if these strings will be loaded once (avoid calling context.getString on each call)?
biodranik commented 2024-04-19 07:40:05 +00:00 (Migrated from github.com)
Review

Does caching the locale help to speed up the method?

Are there other alternatives to String.format?

Does caching the locale help to speed up the method? Are there other alternatives to String.format?
Review

Are there other alternatives to String.format?

I've made some timing comparison with 2 other alternatives to String.format().

You can find the code for this comparison in the function formatMeasurements().

  • Option 1: String.format(Locale, double)
  • Option 2: DecimalFormat("#.#").format(double)
  • Option 3: Long.toString(Math.round(speedValue * 10.0)) + StringBuffer(String).insert(1, char) (inserting the decimal separator into the string)

These are the average times for each option:

  • Option 1: 250 us
  • Option 2: 55 us
  • Option 3: 15 us

Option 3 is by far the fastest one, though it requires to insert manually the decimal separator into the string (as we are doing in c++ right now).

With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements:

Current / New  / Diff (x1.1f)
    210 /   27 / -184 (x0.1)
    123 /   45 /  -78 (x0.4)
    111 /   20 /  -90 (x0.2)
    112 /   21 /  -91 (x0.2)
    115 /   18 /  -97 (x0.2)
    112 /   25 /  -87 (x0.2)
    132 /   22 / -110 (x0.2)
    126 /   23 / -103 (x0.2)
    123 /   29 /  -94 (x0.2)
    120 /   22 /  -97 (x0.2)
    185 /   28 / -156 (x0.2)
    140 /   44 /  -97 (x0.3)
    123 /   22 / -101 (x0.2)
    130 /   26 / -104 (x0.2)
    111 /   22 /  -89 (x0.2)
    108 /   16 /  -92 (x0.1)
    123 /   20 / -103 (x0.2)
    120 /   29 /  -91 (x0.2)
    127 /   21 / -106 (x0.2)

This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including:

  1. Delete the native call for speed formatting.
  2. Implement decimal separator change detection.
  3. Update units strings at app startup and when settings are changed.
  4. Implement speed formatting unit tests in Android

I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.

> Are there other alternatives to String.format? I've made some timing comparison with 2 other alternatives to `String.format()`. You can find the code for this comparison in the function `formatMeasurements()`. - Option 1: `String.format(Locale, double)` - Option 2: `DecimalFormat("#.#").format(double)` - Option 3: `Long.toString(Math.round(speedValue * 10.0))` + `StringBuffer(String).insert(1, char)` (inserting the decimal separator into the string) These are the average times for each option: - Option 1: 250 us - Option 2: 55 us - Option 3: 15 us Option 3 is _by far_ the fastest one, though it requires to insert _manually_ the decimal separator into the string (as we are doing in c++ right now). With option 3, we even get a better performance compared to the current JNI calls. These are the new measurements: ``` Current / New / Diff (x1.1f) 210 / 27 / -184 (x0.1) 123 / 45 / -78 (x0.4) 111 / 20 / -90 (x0.2) 112 / 21 / -91 (x0.2) 115 / 18 / -97 (x0.2) 112 / 25 / -87 (x0.2) 132 / 22 / -110 (x0.2) 126 / 23 / -103 (x0.2) 123 / 29 / -94 (x0.2) 120 / 22 / -97 (x0.2) 185 / 28 / -156 (x0.2) 140 / 44 / -97 (x0.3) 123 / 22 / -101 (x0.2) 130 / 26 / -104 (x0.2) 111 / 22 / -89 (x0.2) 108 / 16 / -92 (x0.1) 123 / 20 / -103 (x0.2) 120 / 29 / -91 (x0.2) 127 / 21 / -106 (x0.2) ``` This 3rd option seems to be a good solution performance-wise, so we could start to implement it in this PR, including: 1. Delete the native call for speed formatting. 2. Implement decimal separator change detection. 3. Update units strings at app startup and when settings are changed. 4. Implement speed formatting unit tests in Android I have to check also if Android Auto also uses native calls for speed formatting, and see if this solution also applies there.
biodranik commented 2024-04-20 15:44:11 +00:00 (Migrated from github.com)
Review

What about separating thousands? There are also Formatter formatter = new Formatter(sb, Locale.US); and java.text.NumberFormat

Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android.

As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?

What about separating thousands? There are also `Formatter formatter = new Formatter(sb, Locale.US);` and `java.text.NumberFormat` Note that there are also values displayed in the Place Page (altitude, speed) that also should be formatted. Ideally, doing it in one place and supporting only one implementation would be the best way to go than supporting C++ version and custom Java formatters for Android. As you've already established a test environment, does it make sense to check how the current C++ implementation can be sped up? Is there any overhead there? Can JNI calls be optimized?
Review

Hello again @biodranik !!

I've made a few more tests / benchmarks for the speed format in Java, using different implementations:

  • Option 1: String.format()
  • Option 2: DecimalFormat class
  • Option 3: Long.toString() + StringBuffer.insert()
  • Option 4: Formatter class
  • Option 5: NumberFormat class

And here is a sample of time values measured while running on an actual Android device:

  Opt1 /  Opt2 /  Opt3 /  Opt4 /  Opt5 (values in us)
   439 /    99 /    29 /   299 /    61
   391 /    72 /    25 /   266 /    60
   403 /   101 /    22 /   311 /    93
   476 /   104 /    45 /   649 /   229
   387 /    75 /    20 /   254 /    60
   821 /    82 /    25 /   305 /    76
   434 /    73 /    20 /   231 /    58
   480 /    76 /    20 /   275 /    65
   435 /    97 /    31 /   404 /   161
   377 /    77 /    20 /   300 /    69
   595 /   119 /    23 /   354 /    74
   399 /   130 /    35 /   467 /   121
   310 /    66 /    19 /   333 /    73
   344 /    68 /    18 /   390 /    88
   504 /   230 /    38 /   476 /    62

The fastest implementation is always Option 3: using Long.toString() and inserting the decimal separator "manually".
This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale().

Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).

Hello again @biodranik !! I've made a few more tests / benchmarks for the speed format in Java, using different implementations: * Option 1: String.format() * Option 2: DecimalFormat class * Option 3: Long.toString() + StringBuffer.insert() * Option 4: Formatter class * Option 5: NumberFormat class And here is a sample of time values measured while running on an actual Android device: ``` Opt1 / Opt2 / Opt3 / Opt4 / Opt5 (values in us) 439 / 99 / 29 / 299 / 61 391 / 72 / 25 / 266 / 60 403 / 101 / 22 / 311 / 93 476 / 104 / 45 / 649 / 229 387 / 75 / 20 / 254 / 60 821 / 82 / 25 / 305 / 76 434 / 73 / 20 / 231 / 58 480 / 76 / 20 / 275 / 65 435 / 97 / 31 / 404 / 161 377 / 77 / 20 / 300 / 69 595 / 119 / 23 / 354 / 74 399 / 130 / 35 / 467 / 121 310 / 66 / 19 / 333 / 73 344 / 68 / 18 / 390 / 88 504 / 230 / 38 / 476 / 62 ``` The fastest implementation is *always* Option 3: using Long.toString() and inserting the decimal separator "manually". This "manual" approach is more or less the same as the one that we have running in c++ in function ToStringPrecisionLocale(). Note that we're dealing here with speed formatting, so only decimal separator is formatted (No thousands separator).
Review

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";".

  • Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
  • Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
  • Option 3: Java formatting implementation (Option 3 in previous benchmarking)

This new second implementation is usually faster that the current one (but always slower than the 3rd implementation: fast Java manual approach):

1=  166 / 2=  144 / 3=   37
1=  159 / 2=  412 / 3=   70
1=  159 / 2=  147 / 3=   36
1=  181 / 2=  159 / 3=   42
1=  157 / 2=  145 / 3=   39
1=  430 / 2=  669 / 3=   58
1=  141 / 2=  118 / 3=   32
1=  537 / 2=  149 / 3=   39
1=  155 / 2=  119 / 3=   32
1=  223 / 2=  137 / 3=   35
1=  142 / 2=  108 / 3=   30
1=  169 / 2=  125 / 3=   33
1=  145 / 2=  139 / 3=   37

Is it worth the implementation of this second approach? It's debatable...

Any feedback is welcomed!!

For the benchmarking of the current c++ implementation, I've implemented an additional JNI call for speed formatting that, instead of returning a Pair<String, String> class, returns a single String class with both the value and unit separated by a semicolon ";". * Option 1 (current): native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond); * Option 2 (new): native String nativeStringFormatSpeedAndUnits(double metersPerSecond); * Option 3: Java formatting implementation (Option 3 in previous benchmarking) This new second implementation is _usually_ faster that the current one (but always slower than the 3rd implementation: fast Java manual approach): 1= 166 / 2= 144 / 3= 37 1= 159 / 2= 412 / 3= 70 1= 159 / 2= 147 / 3= 36 1= 181 / 2= 159 / 3= 42 1= 157 / 2= 145 / 3= 39 1= 430 / 2= 669 / 3= 58 1= 141 / 2= 118 / 3= 32 1= 537 / 2= 149 / 3= 39 1= 155 / 2= 119 / 3= 32 1= 223 / 2= 137 / 3= 35 1= 142 / 2= 108 / 3= 30 1= 169 / 2= 125 / 3= 33 1= 145 / 2= 139 / 3= 37 Is it worth the implementation of this second approach? It's debatable... Any feedback is welcomed!!
biodranik commented 2024-08-08 22:14:50 +00:00 (Migrated from github.com)
Review

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

Thanks! Very interesting measurements. Let's check if we can make C++ code faster first )

View file

@ -30,6 +30,7 @@ public class StringUtils
public static native String[] nativeFilterContainsNormalized(String[] strings, String substr);
public static native Pair<String, String> nativeFormatSpeedAndUnits(double metersPerSecond);
public static native String nativeStringFormatSpeedAndUnits(double metersPerSecond);
public static native Distance nativeFormatDistance(double meters);
@NonNull
public static native Pair<String, String> nativeGetLocalizedDistanceUnits();

View file

@ -1,6 +1,7 @@
package app.organicmaps.widget.menu;
import android.location.Location;
import android.util.Log;
import android.util.Pair;
import android.view.View;
import android.widget.Button;
@ -15,12 +16,16 @@ import app.organicmaps.location.LocationHelper;
import app.organicmaps.routing.RoutingInfo;
import app.organicmaps.sound.TtsPlayer;
import app.organicmaps.util.Graphics;
import app.organicmaps.util.Speed;
import app.organicmaps.util.StringUtils;
import app.organicmaps.util.UiUtils;
import app.organicmaps.util.log.Logger;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
public class NavMenu
@ -203,22 +208,57 @@ public class NavMenu
mTimeEstimate.setText(localTime.format(DateTimeFormatter.ofPattern(format)));
}
private void updateSpeedView(@NonNull RoutingInfo info)
private void updateSpeedView(@NonNull RoutingInfo info, int units)
{
final Location last = LocationHelper.from(mActivity).getSavedLocation();
if (last == null)
return;
// Log measurements for different Java implementations.
Speed.formatMeasurements(last.getSpeed(), units, mActivity.getApplicationContext());
// Speed formatting using native calls.
long start1 = System.nanoTime();
Pair<String, String> speedAndUnits = StringUtils.nativeFormatSpeedAndUnits(last.getSpeed());
long elapsed1 = System.nanoTime() - start1;
mSpeedUnits.setText(speedAndUnits.second);
mSpeedValue.setText(speedAndUnits.first);
// Speed formatting using native calls. Speed and units is returned in a single string.
long start2 = System.nanoTime();
String speedAndUnitsString = StringUtils.nativeStringFormatSpeedAndUnits(last.getSpeed());
// Speed and units are separated by semicolon ";" in returned string.
int separatorPos = speedAndUnitsString.indexOf(";");
String speedString = speedAndUnitsString.substring(0, separatorPos);
String unitsString = speedAndUnitsString.substring(separatorPos + 1);
long elapsed2 = System.nanoTime() - start2;
mSpeedUnits.setText(speedString);
mSpeedValue.setText(unitsString);
// Speed formatting using Android Java calls.
long start3 = System.nanoTime();
speedAndUnits = Speed.format(last.getSpeed(), units, mActivity.getApplicationContext());
long elapsed3 = System.nanoTime() - start3;
mSpeedUnits.setText(speedAndUnits.second);
mSpeedValue.setText(speedAndUnits.first);
String text = String.format(Locale.US,
"Native calls: %5d / %5d / %5d",
Math.round(0.001 * elapsed1),
Math.round(0.001 * elapsed2),
Math.round(0.001 * elapsed3));
Logger.i("LOCALE_MEASURE", text);
mSpeedViewContainer.setActivated(info.isSpeedLimitExceeded());
}
public void update(@NonNull RoutingInfo info)
public void update(@NonNull RoutingInfo info, int units)
{
updateSpeedView(info);
updateSpeedView(info, units);
updateTime(info.totalTimeInSeconds);
mDistanceValue.setText(info.distToTarget.mDistanceStr);
mDistanceUnits.setText(info.distToTarget.getUnitsStr(mActivity.getApplicationContext()));