Skip to content

Commit

Permalink
Better document our macros.
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexhuszagh committed Sep 12, 2024
1 parent 0ac2c92 commit a92dcd4
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 24 deletions.
61 changes: 49 additions & 12 deletions lexical-benchmark/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import argparse
import json
import re
from pathlib import Path

home = Path(__file__).absolute().parent
Expand Down Expand Up @@ -68,41 +69,77 @@
with args.new.open(encoding='utf-8') as fp:
new = json.load(fp)


def numsort(value):
'''We want to sort on the numbers, so say i8 < i32.'''
match = re.search(r'[iuf](\d{1,3})', value)
if match is None:
return value
numeric = match.group(1).rjust(3, '0')
return value[:match.start() + 1] + numeric + value[match.end() + 1:]


# grab our comparison names, so we know where to analyze
group = next(iter(baseline.values()))
tools = sorted({i.rsplit('_')[-1] for i in group['mean']})
header = f'| | {" | ".join(tools)} |'
center = f'|:{"-:|:" * len(tools)}-:|'

# NOTE: These values are in nanoseconds. so, we want to
# then scale it to the appropriate value accordingly


def get_unit(x, y):
def get_unit(x):
'''Get the correct unit suffix and scaling factor.'''
less = min(x, y)
if less > 10**9:
if x < 10**3:
return ('ns', 1)
elif less > 10**6:
elif x < 10**6:
return ('us', 1/10**3)
elif less > 10**3:
elif x < 10**9:
return ('ms', 1/10**6)
return ('s', 1/10**9)


output = 'Results\n=======\n\n' + header + '\n' + center + '\n'
def get_compare_unit(x, y):
'''Get the correct unit suffix and scaling factor.'''
return get_unit(min(x, y))


ratios = []
raw_values = []
first_tool = tools[0]
for test_group, baseline_results in baseline.items():
new_means = new[test_group]['mean']
baseline_means = baseline_results['mean']
tests = sorted([i[: -len(first_tool) - 1] for i in baseline_means if i.endswith(f'_{first_tool}')])
tests = [i[: -len(first_tool) - 1] for i in baseline_means if i.endswith(f'_{first_tool}')]
tests.sort(key=numsort)
for test in tests:
row = []
ratio_row = []
value_row = []
for tool in tools:
test_name = f'{test_group}/{test}' if test_group not in test else test
baseline_mean = baseline_means[f'{test}_{tool}']
new_mean = new_means[f'{test}_{tool}']
row.append(str(round(baseline_mean / new_mean * 100, 2)) + '%')
output += f'| {test} | {" | ".join(row)} |\n'
ratio_row.append(str(round(new_mean * 100 / baseline_mean, 2)) + '%')
unit, scale = get_compare_unit(new_mean, baseline_mean)
value_row.append(str(round(new_mean * scale, 4)) + unit)
value_row.append(str(round(baseline_mean * scale, 4)) + unit)
ratios.append(f'| {test_name} | {" | ".join(ratio_row)} |')
raw_values.append(f'| {test_name} | {" | ".join(value_row)} |')

ratio_header = f'| | {" | ".join(tools)} |'
ratio_center = f'|:{"-:|:" * len(tools)}-:|'
pairs = [j for i in tools for j in (f'{i} - New', f'{i} - Base')]
value_header = f'| | {" | ".join(pairs)} |'
value_center = f'|:{"-:|:" * len(tools) * 2}-:|'

output = '# Results\n\n'
output += '## Ratios\n\n'
output += 'These results are calculated as `new / baseline`, so values below 100% are better.\n\n'
output += f'{ratio_header}\n{ratio_center}\n'
output += '\n'.join(ratios)
output += '\n\n## Raw Values\n\n'
output += f'{value_header}\n{value_center}\n'
output += '\n'.join(raw_values)


with args.output.open('w', encoding='utf-8') as file:
print(output, file=file)
25 changes: 25 additions & 0 deletions lexical-benchmark/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ macro_rules! json_data {
}

/// Generate an array of values as static data
///
/// - `fn` - The name to register the static data as
/// - `cb` - The function to fetch the data
/// - `f1` - The field within the data to fetch
#[allow(unknown_lints, unused_macro_rules)]
macro_rules! static_data {
($($fn:ident $cb:ident $f1:ident $t:tt ; )*) => ($(
Expand Down Expand Up @@ -162,6 +166,12 @@ pub trait IntegerRng: NumberRng + Integer {
fn large_signed(rng: &mut Rng) -> String;
}

/// Generate an unsigned, random range for testing.
///
/// - `min` - The min for simple values
/// - `max` - The max for simple values
/// - `lmin` - The min for large values
/// - `lmax` - The max for large values
#[cfg(feature = "integers")]
macro_rules! unsigned_rng {
($($t:ident $smin:literal $smax:literal $lmin:literal $lmax:literal ; )*) => ($(
Expand Down Expand Up @@ -207,6 +217,16 @@ macro_rules! unsigned_rng {
)*);
}

/// Generate a signed, random range for testing.
///
/// - `smin` - The min for simple values
/// - `smax` - The max for simple values
/// - `ssmin` - The min for signed, simple values
/// - `ssmax` - The max for signed, simple values
/// - `lmin` - The min for large values
/// - `lmax` - The max for large values
/// - `lsmin` - The min for signed, large values
/// - `lsmax` - The max for signed, large values
#[cfg(feature = "integers")]
macro_rules! signed_rng {
($(
Expand Down Expand Up @@ -379,6 +399,11 @@ where

// GENERATORS

// For all of these:
// - `group`: The name of the group containing mutiple benches.
// - `name`: The name of the bench within the group.
// - `iter`: An abstract iterable over the data to process.

macro_rules! to_lexical_generator {
($group:ident, $name:expr, $iter:expr) => {{
use lexical_util::constants::BUFFER_SIZE;
Expand Down
14 changes: 12 additions & 2 deletions lexical-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,12 @@ to_lexical!();
#[cfg(feature = "write")]
to_lexical_with_options!();

/// Implement `FromLexical` and `FromLexicalWithOptions` for numeric type.
/// Implement `FromLexical` and `FromLexicalWithOptions` for numeric types.
///
/// * `t` - The numerical type.
/// * `from` - The internal trait that implements `from_lexical`.
/// * `from_lexical_with_options` - The internal trait that implements `from_lexical`.
/// * `options` - The options type to configure settings.
#[cfg(feature = "parse")]
macro_rules! from_lexical_impl {
($t:ident, $from:ident, $from_options:ident, $options:ident) => {
Expand Down Expand Up @@ -460,7 +465,12 @@ macro_rules! float_from_lexical {
#[cfg(feature = "parse-floats")]
float_from_lexical! { f32 f64 }

// Implement ToLexical for numeric type.
/// Implement `ToLexical` and `ToLexicalWithOptions` for numeric types.
///
/// * `t` - The numerical type.
/// * `to` - The internal trait that implements `to_lexical`.
/// * `to_lexical_with_options` - The internal trait that implements `to_lexical`.
/// * `options` - The options type to configure settings.
#[cfg(feature = "write")]
macro_rules! to_lexical_impl {
($t:ident, $to:ident, $to_options:ident, $options:ident) => {
Expand Down
2 changes: 2 additions & 0 deletions lexical-parse-float/src/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ pub struct StackVec<const SIZE: usize> {
/// NOTE: Modifying this to remove unsafety which we statically
/// check directly in every caller leads to ~20% degradation in
/// performance.
/// - `rview` - A reversed view over a slice.
/// - `fn` - The callback to extract the high bits.
macro_rules! hi {
(@1 $self:ident, $rview:ident, $t:ident, $fn:ident) => {{
$fn(unsafe { index_unchecked!($rview[0]) as $t })
Expand Down
2 changes: 1 addition & 1 deletion lexical-parse-float/src/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn parse_u64_digits<'a, Iter, const FORMAT: u128>(

// Try to parse 8 digits at a time, if we can.
#[cfg(not(feature = "compact"))]
if can_try_parse_8digits!(iter, radix) {
if can_try_parse_multidigit!(iter, radix) {
debug_assert!(radix < 16);
let radix8 = format.radix8() as u64;
while *step > 8 {
Expand Down
2 changes: 2 additions & 0 deletions lexical-parse-float/src/libm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
* ====================================================
*/

/// Index an array without bounds checking.
///
/// # Safety
///
/// Safe if `index < array.len()`.
Expand Down
13 changes: 11 additions & 2 deletions lexical-parse-float/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ pub fn parse_exponent_sign<const FORMAT: u128>(byte: &mut Bytes<'_, FORMAT>) ->
}

/// Utility to extract the result and handle any errors from parsing a `Number`.
///
/// - `format` - The numberical format as a packed integer
/// - `byte` - The BytesIter iterator
/// - `is_negative` - If the final value is negative
/// - `parse_normal` - The function to parse non-special numbers with
/// - `parse_special` - The function to parse special numbers with
macro_rules! parse_number {
(
$format:ident,
Expand All @@ -266,6 +272,9 @@ macro_rules! parse_number {
}

/// Convert extended float to native.
///
/// - `type` - The native floating point type.
/// - `fp` - The extended floating-point representation.
macro_rules! to_native {
($type:ident, $fp:ident, $is_negative:ident) => {{
let mut float = extended_to_float::<$type>($fp);
Expand Down Expand Up @@ -831,7 +840,7 @@ where
{
let format = NumberFormat::<{ FORMAT }> {};
let radix: u64 = format.radix() as u64;
if can_try_parse_8digits!(iter, radix) {
if can_try_parse_multidigit!(iter, radix) {
debug_assert!(radix < 16);
let radix8 = format.radix8() as u64;
// Can do up to 2 iterations without overflowing, however, for large
Expand Down Expand Up @@ -860,7 +869,7 @@ pub fn parse_u64_digits<'a, Iter, const FORMAT: u128>(

// Try to parse 8 digits at a time, if we can.
#[cfg(not(feature = "compact"))]
if can_try_parse_8digits!(iter, radix) {
if can_try_parse_multidigit!(iter, radix) {
debug_assert!(radix < 16);
let radix8 = format.radix8() as u64;
while *step > 8 {
Expand Down
4 changes: 2 additions & 2 deletions lexical-parse-float/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use lexical_util::num::AsPrimitive;
// 8 DIGIT
// -------

/// Check if we can try to parse 8 digits.
/// Check if we can try to parse 8 digits at one.
#[cfg(not(feature = "compact"))]
macro_rules! can_try_parse_8digits {
macro_rules! can_try_parse_multidigit {
($iter:expr, $radix:expr) => {
$iter.is_contiguous() && (cfg!(not(feature = "power-of-two")) || $radix <= 10)
};
Expand Down
42 changes: 41 additions & 1 deletion lexical-parse-float/src/slow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,14 @@ pub fn negative_digit_comp<F: RawFloat, const FORMAT: u128>(
}

/// Try to parse 8 digits at a time.
///
/// - `format` - The numerical format specification as a packed 128-bit integer
/// - `iter` - An iterator over all bytes in the buffer
/// - `value` - The currently parsed value.
/// - `count` - The total number of parsed digits
/// - `counter` - The number of parsed digits since creating the current u32
/// - `step` - The maximum number of digits for the radix that can fit in a u32.
/// - `max_digits` - The maximum number of digits that can affect floating-point rounding.
#[cfg(not(feature = "compact"))]
macro_rules! try_parse_8digits {
(
Expand All @@ -257,7 +265,7 @@ macro_rules! try_parse_8digits {
let radix = format.radix() as Limb;

// Try 8-digit optimizations.
if can_try_parse_8digits!($iter, radix) {
if can_try_parse_multidigit!($iter, radix) {
debug_assert!(radix < 16);
let radix8 = format.radix8() as Limb;
while $step - $counter >= 8 && $max_digits - $count >= 8 {
Expand All @@ -274,6 +282,11 @@ macro_rules! try_parse_8digits {
}

/// Add a digit to the temporary value.
///
/// - `c` - The character to convert to a digit.
/// - `value` - The currently parsed value.
/// - `count` - The total number of parsed digits
/// - `counter` - The number of parsed digits since creating the current u32
macro_rules! add_digit {
($c:ident, $radix:ident, $value:ident, $counter:ident, $count:ident) => {{
let digit = char_to_valid_digit_const($c, $radix);
Expand All @@ -287,6 +300,12 @@ macro_rules! add_digit {
}

/// Add a temporary value to our mantissa.
///
/// - `format` - The numerical format specification as a packed 128-bit integer
/// - `result` - The big integer,
/// - `power` - The power to scale the big integer by.
/// - `value` - The value to add to the big intger,
/// - `counter` - The number of parsed digits since creating the current u32
macro_rules! add_temporary {
// Multiply by the small power and add the native value.
(@mul $result:ident, $power:expr, $value:expr) => {
Expand All @@ -312,6 +331,10 @@ macro_rules! add_temporary {
}

/// Round-up a truncated value.
///
/// - `format` - The numerical format specification as a packed 128-bit integer
/// - `result` - The big integer,
/// - `count` - The total number of parsed digits
macro_rules! round_up_truncated {
($format:ident, $result:ident, $count:ident) => {{
// Need to round-up.
Expand All @@ -323,6 +346,11 @@ macro_rules! round_up_truncated {
}

/// Check and round-up the fraction if any non-zero digits exist.
///
/// - `format` - The numerical format specification as a packed 128-bit integer
/// - `iter` - An iterator over all bytes in the buffer
/// - `result` - The big integer,
/// - `count` - The total number of parsed digits
macro_rules! round_up_nonzero {
($format:ident, $iter:expr, $result:ident, $count:ident) => {{
// NOTE: All digits must be valid.
Expand Down Expand Up @@ -454,6 +482,10 @@ pub fn parse_mantissa<const FORMAT: u128>(num: Number, max_digits: usize) -> (Bi
}

/// Compare actual integer digits to the theoretical digits.
///
/// - `iter` - An iterator over all bytes in the buffer
/// - `num` - The actual digits of the real floating point number.
/// - `den` - The theoretical digits created by `b+h` to determine if `b` or `b+1`
#[cfg(feature = "radix")]
macro_rules! integer_compare {
($iter:ident, $num:ident, $den:ident, $radix:ident) => {{
Expand Down Expand Up @@ -487,6 +519,10 @@ macro_rules! integer_compare {
}

/// Compare actual fraction digits to the theoretical digits.
///
/// - `iter` - An iterator over all bytes in the buffer
/// - `num` - The actual digits of the real floating point number.
/// - `den` - The theoretical digits created by `b+h` to determine if `b` or `b+1`
#[cfg(feature = "radix")]
macro_rules! fraction_compare {
($iter:ident, $num:ident, $den:ident, $radix:ident) => {{
Expand Down Expand Up @@ -623,6 +659,10 @@ pub fn byte_comp<F: RawFloat, const FORMAT: u128>(
}

/// Compare digits between the generated values the ratio and the actual view.
///
/// - `number` - The representation of the float as a big number, with the parsed digits.
/// - `num` - The actual digits of the real floating point number.
/// - `den` - The theoretical digits created by `b+h` to determine if `b` or `b+1`
#[cfg(feature = "radix")]
pub fn compare_bytes<const FORMAT: u128>(
number: Number,
Expand Down
Loading

0 comments on commit a92dcd4

Please sign in to comment.