Skip to content

Conversation

squeek502
Copy link
Collaborator

@squeek502 squeek502 commented Oct 31, 2023

This takes the ASCII fast path added for UTF-8 validation in #17329 (plus the changes in #17659) and applies the same concept to both directions of UTF-8 <-> UTF-16 conversion.

I'm new to SIMD stuff so feedback on the implementation is appreciated.

Benchmark results

Benchmark code
const std = @import("std");

const ITERATIONS = 20_000;

pub fn main() !void {
    try benchmark(
        "short.ascii",
        "it's over 9000!!",
        16,
    );
    std.debug.print("\n", .{});
    try benchmark(
        "long.ascii",
        "Lorem ipsum dolor sit amet, pri legere suscipit repudiare at, cu vix aliquip pertinacia quaerendum, in eam dicat cetero eripuit. Duo odio nonumy viderer at, et sea vidit dolor animal, has persius conceptam id. Vide idque copiosae ut qui, ut lorem atomorum mei, in eos suscipit eleifend. Illud principes no eos, pri dolorem singulis ne, ex pri malorum argumentum scribentur. Et altera regione per. Disputando contentiones no mei, et vel discere meliore constituam. Te quo legere nostrum deleniti, ad eros putent tritani per.Repudiandae mediocritatem ut est, ex sea dicit evertitur. Per tritani detraxit an. Pro no fastidii tractatos, per purto affert accusata no, affert consequat mel ea. Cum ex postulant gubergren, has quot vidit argumentum no.Eu est esse feugait, mea no augue debet constituam. Sea stet augue libris no, affert fierent in sea, mei soluta cetero corrumpit ex. Iriure saperet has ut. Quem mucius maiestatis ea mea. Cum eu partiendo complectitur. Ei quo veri lobortis percipitur, te velit maluisset tincidunt mel. Has ei debet munere menandri.Tempor sententiae eu mel, id mei facete necessitatibus, qui ei vocibus commune. Case minimum an nam. Ut magna solet democritum ius, eu vix iudico eirmod ceteros. Has ea labore voluptua postulant. Reque atqui vocent an sit, usu tritani dissentias ei, ius id aperiri elaboraret disputando. Vis cu audire neglegentur, viderer habemus offendit pro et, sed at forensibus voluptaria philosophia.Pro no hinc cibo euripidis. Eum in eirmod expetendis, cibo aeque has ei, duo at graeco eripuit assentior. Mei omnis partem debitis eu, latine consetetur has ei. Vix primis repudiandae te, qui vide assentior te. Vel amet tollit consequuntur id. Facilisi principes ad mei, congue blandit contentiones eos at, ius justo honestatis eu.Tractatos disputando at eum, pro cu iisque epicurei. Integre aliquam scaevola ei vis, te euismod meliore qui. Ius scripta detracto disputationi cu. Ea vel expetenda dissentiunt, primis iracundia adversarium nam eu, meis ubique efficiantur est ea. Eos nominavi inimicus torquatos in, eum graecis scribentur vituperatoribus ne, amet eloquentiam vel ut.At luptatum accusata signiferumque mea. Cibo omnis ut mea. Sea meis primis commune ad, quot facer disputationi eum eu. Eu probo ridens sit, nam ei cibo fabulas, integre aliquid invidunt no usu.Ea wisi fuisset lobortis eos, eu facer corrumpit sed. Te cetero petentium persecuti duo. Duo te mucius inermis adversarium, mea no modus percipitur. Ad tation appetere cum, quo latine dolorem te. Aliquando definiebas necessitatibus te ius, te est error albucius postulant.Laoreet molestiae gloriatur id per, ut vis oporteat dissentias. Ius admodum abhorreant ad, duo no primis minimum sapientem. Eam ne scaevola apeirian adipiscing, cu mea causae detracto percipitur. Ut movet invenire his, eu mea tota docendi accusata, no singulis lobortis ullamcorper eos.Option virtute adversarium quo ei, sed ex mandamus efficiendi. Ad per omnium dissentias. Sonet vocibus eu sit, ut soleat menandri mei. Nec cu noster tincidunt, vidit legere ex sed. Viderer discere cum ea.Ad vis postea labitur suscipiantur, temporibus contentiones duo at. Cu admodum mentitum eos, viris luptatum interesset pro ad, ea nominati erroribus cum. Vix nonumy ridens ut, ut cum equidem maiorum. Mei ex iudico accusam, mentitum antiopam ut est. Docendi consulatu vis ut, vel ut dicit accumsan, est mundi epicuri intellegam no.Duo odio vivendum contentiones in, cu enim accusata voluptatibus quo. Quando alterum ancillae ne eam, nisl tractatos intellegam ne per. Eu vide percipitur qui, ius ad utamur persecuti. Purto deleniti sed ad, quis urbanitas has ei. Ad vel dolorem tractatos repudiare.Oratio aperiam suavitate nam ei, cu probo aliquando accommodare sit. Pro ei repudiare cotidieque, aperiri nostrum expetendis ei pro. Habeo quodsi salutatus sit no, per decore aliquam cu. Nostrum efficiantur an est. Ei ius dico nibh vidisse.Tantas ubique scripserit te quo, decore labitur insolens eu vim. Ad vix fugit conceptam dissentias, eam posse ipsum nullam te. Quo at recusabo accusamus, nam eu enim feugiat, ius ad postulant disputando comprehensam. Iusto eruditi epicurei at mei, his te phaedrum deseruisse. An his congue veniam, id vix erat fierent, adipisci sensibus id eam. Ei quem sensibus gubergren nec, at per soleat accommodare. Viderer nominavi rationibus his ei, per et etiam scriptorem.Cetero scripserit vim ad. Ea case modus comprehensam cum, viris audire ius cu. Veri albucius ius ex, ei solum expetendis intellegebat nec. Pri ne ancillae consulatu urbanitas. Nisl debet vis ad, ei mea graecis maluisset accusamus. Scripta euismod vivendum est no. Duo ludus pertinacia ea, an nonumy detracto nam.Veniam fuisset dolores ei nam, cum eu soluta essent graecis. Sale dictas est eu. An denique omnesque molestie sea, unum labore deterruisset mea no, dolore persecuti ut est. Et sit dictas maluisset. Ex quod solum euismod his.Cum affert scaevola gloriatur no, modus saperet similique id pri. Mutat ludus in per, per at erat lobortis elaboraret. Vis cetero ancillae ne, his rationibus suscipiantur necessitatibus ne. Eum dicant possit eleifend no. Ne paulo numquam per. An dicta nonumes eos.Mea quidam complectitur et, nihil noster et mel, vim an debet quaestio. Te ius fugit aliquid corpora, vim animal deterruisset an. Cum at nusquam omittantur, et sit assum repudiare, mei molestie sadipscing omittantur an. Sit viris euismod cu, vis tation legere percipit ad. Oratio aperiri laboramus eos no. Ne postea voluptatibus mel.Vim ad viris elitr iudicabit, ea quot debet cotidieque vel. Purto vitae nonumes id has. Eruditi philosophia vel an. Eum at primis impetus ullamcorper, mei quot percipit argumentum at. Tota admodum molestie vis ad, eu est percipit interesset, legimus indoctum pertinacia id his. Gubergren philosophia cu sed, eum ei erant soleat. Ex vix detraxit vituperata, liber persius voluptua qui ne. Ad mel qualisque concludaturque, docendi pertinax ea eos, ei sit iudico democritum interesset. Ut albucius vivendum disputationi sit, senserit mnesarchum usu ut. Facilisis argumentum necessitatibus nec ei, nonumes accusamus vis ea.",
        6136,
    );
}

fn benchmark(name: []const u8, input: []const u8, expected_len: usize) !void {
    var utf16: [10000]u16 = undefined;
    var utf8: [16000]u8 = undefined;
    std.debug.assert(utf16.len >= input.len);
    std.debug.assert(utf16.len >= expected_len);

    var timer = try std.time.Timer.start();

    for (0..ITERATIONS) |_| {
        if (try std.unicode.utf8ToUtf16Le(&utf16, input) != expected_len) {
            @panic("fail");
        }
    }
    std.debug.print("{s}:utf8->utf16.buf:     {d}\n", .{ name, timer.lap() / ITERATIONS });

    timer.reset();
    for (0..ITERATIONS) |_| {
        var fba = std.heap.FixedBufferAllocator.init(std.mem.sliceAsBytes(&utf16));
        const allocator = fba.allocator();
        const allocated_utf16 = try std.unicode.utf8ToUtf16LeWithNull(allocator, input);
        defer allocator.free(allocated_utf16);
        if (allocated_utf16.len != expected_len) {
            @panic("fail");
        }
    }
    std.debug.print("{s}:utf8->utf16.alloc:   {d}\n", .{ name, timer.lap() / ITERATIONS });

    _ = try std.unicode.utf8ToUtf16Le(&utf16, input);
    const utf16_input = utf16[0..expected_len];

    timer.reset();
    for (0..ITERATIONS) |_| {
        if (try std.unicode.utf16leToUtf8(&utf8, utf16_input) != input.len) {
            @panic("fail");
        }
    }
    std.debug.print("{s}:utf16->utf8.buf:     {d}\n", .{ name, timer.lap() / ITERATIONS });

    timer.reset();
    for (0..ITERATIONS) |_| {
        var fba = std.heap.FixedBufferAllocator.init(&utf8);
        const allocator = fba.allocator();
        const allocated_utf8 = try std.unicode.utf16leToUtf8Alloc(allocator, utf16_input);
        defer allocator.free(allocated_utf8);
        if (allocated_utf8.len != input.len) {
            @panic("fail");
        }
    }
    std.debug.print("{s}:utf16->utf8.alloc:   {d}\n", .{ name, timer.lap() / ITERATIONS });
}

ReleaseFast

benchmark before (ns per iter) after (ns per iter) times faster
short.ascii:utf8->utf16.buf 140 143 -
short.ascii:utf8->utf16.alloc 152 154 -
short.ascii:utf16->utf8.buf 58 2 29x
short.ascii:utf16->utf8.alloc 68 10 6.8x
long.ascii:utf8->utf16.buf 53549 479 111.8x
long.ascii:utf8->utf16.alloc 55872 509 109.8x
long.ascii:utf16->utf8.buf 17764 314 56.6x
long.ascii:utf16->utf8.alloc 20649 321 64.3x

Debug

benchmark before (ns per iter) after (ns per iter) times faster
short.ascii:utf8->utf16.buf 387 376 -
short.ascii:utf8->utf16.alloc 1251 1202 -
short.ascii:utf16->utf8.buf 681 53 12.8x
short.ascii:utf16->utf8.alloc 1127 313 3.6x
long.ascii:utf8->utf16.buf 139944 5365 26.1x
long.ascii:utf8->utf16.alloc 309530 7854 39.4x
long.ascii:utf16->utf8.buf 245714 10018 24.5x
long.ascii:utf16->utf8.alloc 314542 13386 23.5x

Performance for non-ASCII strings is ~unchanged. More complicated techniques would be needed to apply SIMD to conversion of non-ASCII codepoints:


I was slightly expecting this to make a noticeable difference on Windows for filesystem-heavy use cases, but there was no difference in the test I used in this post (recursively copying a giant nested directory). Also no difference in the runtime of the standard library tests.

@squeek502 squeek502 force-pushed the utf16-ascii-fast-path branch from aae4407 to 13c8ec9 Compare October 31, 2023 09:23
@andrewrk
Copy link
Member

I'm also new to SIMD stuff, so I don't have any particular insight for you, but if the code looks good (it does) and it makes it measurably faster (you have demonstrated this) then it's ready to land!

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

Successfully merging this pull request may close these issues.

2 participants