Wc рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рдЕрдиреНрдп рд▓реЗрдЦ

рд╕рдмрдХреЗ рд▓рд┐рдП рджрд┐рди рдЕрдЪреНрдЫрд╛ рд╣реЛред


рд╣рд╛рд▓ рд╣реА рдореЗрдВ рд╣реЗрдмреНрд░рд╛ рд╡рд┐рдирд┐рдВрдЧ рд╡рд┐рде рд╣рд╛рд╕реНрдХреЗрд▓ рдХреА рдмреАрд╕ рдкрдВрдХреНрддрд┐рдпреЛрдВ рдкрд░ рдПрдХ рд▓реЗрдЦ рдЫрдкрд╛ : рд╣рдо @ 0xd34df00d рд╕реЗ рдЕрдкрдирд╛ wc рд▓рд┐рдЦрддреЗ рд╣реИрдВ ред рд▓реЗрдЦрдХ, рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЙрдирдХреА рд╕рд╣рд╛рдиреБрднреВрддрд┐ рдХреЗ рд▓рд┐рдП рдЬрд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рд╛рд╕реНрдХреЗрд▓ рдкрд░ wc рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдФрд░ рдЗрд╕реЗ рдЕрдиреБрдХреВрд▓рди рдХреЗ рдЕрдзреАрди рдХрд┐рдпрд╛, рдЬрд┐рд╕рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╣реИ рдЬреЛ рдорд╛рдирдХ рдпреВрдирд┐рдХреНрд╕ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ 7 рдЧреБрдирд╛ рдЕрдзрд┐рдХ рддреЗрдЬреА рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред


рдПрдХ рдИрдорд╛рдирджрд╛рд░ рдмреЗрдВрдЪрдорд╛рд░реНрдХрд░ рд╣реЛрдиреЗ рдХреЗ рдирд╛рддреЗ, 0xd34df00dрд▓реЗрдЦ рдХреЗ рдЕрдВрдд рдореЗрдВ, рдЙрдиреНрд╣реЛрдВрдиреЗ рд╕рдВрдХреЗрдд рджрд┐рдпрд╛ рдХрд┐ рдЙрдирдХрд╛ рд╕рдВрд╕реНрдХрд░рдг рдореВрд▓ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдмрд╣реБрдд рд╕рд░рд▓ рдЯреАрдХреЗ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпреВрдирд┐рдХреЛрдб рдХреЛ рдЕрдирджреЗрдЦрд╛ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛), рдФрд░ рдЗрд╕рд▓рд┐рдП рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рдЗрд╕рдХреА рд╢реНрд░реЗрд╖реНрдарддрд╛ рдХрд╛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреБрдЫ рднреА рдорддрд▓рдм рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реИ рдХрд┐ рдЗрд╕рдХреЗ рдмрд╛рд╡рдЬреВрдж, рд▓реЗрдЦ рдХреЗ рдкреНрд░рд╛рд░реВрдк рдиреЗ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рдмрд╣реБрдд рд╡рд┐рд╡рд╛рдж рдЙрддреНрдкрдиреНрди рдХрд┐рдпрд╛ (рдФрд░ рдореИрдВ рдЕрдХреНрд╕рд░ рдЦреБрдж рдХреЛ рд╢реАрд░реНрд╖рдХ рд╕реЗ рдЖрдЧреЗ рдирд╣реАрдВ рдкрдврд╝рддрд╛ рд╣реВрдВ, рдЬреЛ рдЫрд┐рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рдк рд╣реИ)ред рд▓реЗрдЦ рдХреЗ рддрд╣рддyleoрдЙрдиреНрд╣реЛрдВрдиреЗ рд╕реА рдореЗрдВ рдЙрдирдХреЗ рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦрд┐рдд рдПрдХ рддреБрдЪреНрдЫ рд╕рдорд╛рдзрд╛рди рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХрд╛ рд╣рд╡рд╛рд▓рд╛ рджрд┐рдпрд╛ (рдПрдХ рд╕рд░рд▓реАрдХреГрдд рд╕реНрдерд┐рддрд┐ рдХреЗ рддрд╣рдд), рдпрд╣ рджрд┐рдЦрд╛рддреЗ рд╣реБрдП рдХрд┐ рдПрдХ рднреЛрд▓реА рд╕реА-рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЕрдиреБрдХреВрд▓рд┐рдд рд╣рд╕реНрдХреЗрд▓-рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рднреА рдмрд╛рдпрдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИред рдЙрд╕рдХреЗ рдмрд╛рдж, рд╕рдЬреНрдЬрдиреЛрдВ рдиреЗ рдЦреБрдж рдХреЛ рдПрдХ рджреВрд╕рд░реЗ рдкрд░ рдлреЗрдВрдХрдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛kaрдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ, рдЬрд┐рд╕рдореЗрдВ рдЙрдиреНрд╣реЛрдВрдиреЗ рдЕрдкрдиреЗ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреА рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдореЗрдВ рдЫреЛрдЯреЗ рдЕрдВрддрд░ рдХреЗ рд╕рд╛рде рдЧрд▓рддреА рдкрд╛рдИ (рдпрд╣ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рд╕реНрдерд┐рддрд┐ рдХреА рдореЗрд░реА рд╡реНрдпрдХреНрддрд┐рдЧрдд рджреГрд╖реНрдЯрд┐ рд╣реИ)ред


рдХреБрдЫ рд╕рдордп рдмрд╛рдж, рдПрдХ рд▓реЗрдЦ рдХреЙрдорд░реЗрдб рдкреНрд░рдХрд╛рд╢рд┐рдд рд╣реБрдЖ chapuza, рдЬрд┐рд╕рдиреЗ рдПрд▓рд┐рдХреНрд╕рд┐рд░ рдкрд░ рд╕рд░рд▓реАрдХреГрдд рдбрдмреНрд▓реНрдпреВрд╕реА рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рд╢реБрд░реБрдЖрдд рдХреА , рдЬреЛ рдорд╛рдирдХ рдПрдХ рд╕реЗ рднреА рддреЗрдЬ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдкрд╣рд▓реА рдкреЛрд╕реНрдЯ рд╕реЗ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рдЪрд░реНрдЪрд╛ рдЬрд╛рд░реА рд░рд╣реА, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдореЗрд░реА рд░рд╛рдп рдореЗрдВ рдкреВрд░реНрд╡ рдлреНрдпреВрдЬ рдЦреЛ рдЧрдпрд╛ рдерд╛ред


рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рд╣рдо рдПрдХ рднрд╛рд╖рд╛ / рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдкреНрд░рддрд┐рдорд╛рди рдХреЛ рджреВрд╕рд░реЗ / рджреВрд╕рд░реЗ рдХреЗ рд╕рд╛рде рдкрд░рд╛рдЬрд┐рдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдПрдХ рдирд┐рд╖реНрдкрдХреНрд╖ рд╡реНрдпрдХреНрддрд┐ рд╕рдордЭрддрд╛ рд╣реИ рдХрд┐ рд╕реА, рд╣рд╛рд╕реНрдХреЗрд▓ рдФрд░ рдЕрдиреНрдп рдЕрдиреНрдп рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рднрд╛рд╖рд╛рдУрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдореИрдиреБрдЕрд▓ рдЕрдиреБрдХреВрд▓рди рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд▓рдЪреАрд▓рд╛ рд╣реИ, рдФрд░ рдЗрд╕рд▓рд┐рдП рд╕реА рдХреЛрдб, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рд╣рд╛рд╕реНрдХреЗрд▓ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдзреАрдорд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдпрд╣ рдмрд╣реБрдд рддреЗрдЬ рднреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ - рдпрд╣ рд╕рдм рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ рдЗрд╕ рдХреЛрдб рдХреЛ рдХреМрди рд▓рд┐рдЦрддрд╛ рд╣реИред рджреВрд╕рд░реА рдУрд░, рдореИрдВ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░рддрд┐рдорд╛рди рдХреА рдмрд╣реБрдд рд╕рд╛рд░реА рд╕рдВрднрд╛рд╡рдирд╛рдПрдВ рджреЗрдЦрддрд╛ рд╣реВрдВ рдЬреЛ рдЕрднреА рддрдХ рдЦреЛрдЬрд╛ рдирд╣реАрдВ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдореИрдВ рдЗрд╕ рд╕рдВрднрд╛рд╡рдирд╛ рдХреЛ рдмрд╛рд╣рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реВрдВ рдХрд┐ рдХрд┐рд╕реА рджрд┐рди рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдХреЛрдб рдХреЛ рдЗрддрдирд╛ рдЕрдЪреНрдЫрд╛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдХрд┐ рд╕реА рдореЗрдВ рдЗрд╕ рддрд░рд╣ рдХрд╛ рдПрдирд╛рд▓реЙрдЧ рд▓рд┐рдЦрдирд╛ рдмрд╣реБрдд рдорд╣рдВрдЧрд╛ рд╣реЛрдЧрд╛ред рд▓реЗрдХрд┐рди рдлрд┐рд░ рднреА, рдпрд╣ рд╕рдордп рдЕрднреА рддрдХ рдирд╣реАрдВ рдЖрдпрд╛ рд╣реИред


, , ( ) , C-. . , , , 0xd34df00d "simd-".



, , .


#include <stdint.h>
#include <stdio.h>
#include <malloc.h>
#include <Windows.h>
#include <intrin.h>

using namespace std;

struct stats
{
    uint32_t char_count;
    uint32_t line_count;
    uint32_t word_count;
};

void word_count( unsigned char* const str, uint32_t size, stats& result );

int main( )
{
    FILE* f;
    fopen_s( &f, "input.txt", "rb" );
    fseek( f, 0, SEEK_END );
    long size = ftell( f );
    rewind( f );

    long alloc_size = size + 63 - ( size + 63 ) % 64;
    unsigned char* const data = (unsigned char*)_aligned_malloc( alloc_size, 64 );
    fread( data, 1, size, f );
    fclose( f );

    LARGE_INTEGER fr, t0, t1;
    QueryPerformanceFrequency( &fr );
    QueryPerformanceCounter( &t0 );

    stats result;
    word_count2( data, size, result );

    QueryPerformanceCounter( &t1 );

    _aligned_free( data );

    double const time = (double)( t1.QuadPart - t0.QuadPart ) / (double)fr.QuadPart;
    printf(
        "Words: %d; lines: %d; chars: %d\nElapsed time: %lfms\n",
        result.word_count, result.line_count, result.char_count, time * 1000.0
    );
    system( "pause" );
}

тАФ , Windows Visual Studio. , Linux' , Linux- . , тАФ VS.


, . , . 64 64 тАФ SIMD-, . , . ( , , , .) , .


, Unicode, 32. , . , , .


Ryzen 5 3600 c 2x8 Gb 3200 MHz. , , .



:


void word_count( unsigned char* const str, uint32_t size, stats& result )
{
    uint32_t lines = 1;
    uint32_t words = 0;

    bool was_space = false;

    for ( uint32_t i = 0; i < size; ++i )
    {
        unsigned char const c = str[i];
        bool const is_space = c <= ' ';
        lines += ( c == '\n' ) ? 1 : 0;
        words += ( is_space && !was_space ) ? 1 : 0;
        was_space = is_space;
    }

    words += !was_space ? 1 : 0;

    result.char_count = size;
    result.line_count = lines;
    result.word_count = words;
}

0xd34df00d. :


Words: 44774640; lines: 15000010; chars: 1871822228
Elapsed time: 1825.704800ms

(SIMD- )


, ? , (, , ). 16 SSE-?


SSE:


void word_count_sse( unsigned char* const str, uint32_t size, stats& result )
{
    uint32_t lines = 1;
    uint32_t words = 0;

    bool was_space = false;

    for ( uint32_t i = 0; i < size; i += 16 )
    {
        __m128i const c = _mm_load_si128( (__m128i*)( str + i ) );
        uint32_t is_newline_mask = _mm_movemask_epi8(
            _mm_cmpeq_epi8( c, _mm_set1_epi8( '\n' ) )
        );

        uint32_t is_space_mask = _mm_movemask_epi8(
            _mm_andnot_si128( c, _mm_cmplt_epi8( c, _mm_set1_epi8( ' ' + 1 ) ) )
        );
        uint32_t was_space_mask = ( was_space ? 1 : 0 ) | ( is_space_mask << 1 );

        lines += __popcnt( is_newline_mask );
        words += __popcnt( is_space_mask & ~was_space_mask );
        was_space = is_space_mask & 0x8000;
    }

    words += !was_space ? 1 : 0;

    result.char_count = size;
    result.line_count = lines;
    result.word_count = words;
}

. was_space, . , 16 , 15- , .


_mm_load_si128 __m128i ( 128- XMM-).


. тАФ 16- , 128- . SSE- XMM-, 16- _mm_movemask_epi8. тАФ 128- , 16 , 16- , XMM-.


_mm_cmpeq_epi8, 128- , 0, , 255 . 128- , ( _mm_set1_epi8).


. , / SSE . _mm_cmplt_epi8 тАФ , _mm_cmpeq_epi8. , , 128 , . _mm_andnot_si128. 128- "" . _mm_cmplt_epi8 . 128 , тАФ , movemask'.


. was_space_mask, is_space_mask was_space, , __popcnt , . was_space , .


SIMD- x86 .


:


Words: 44774640; lines: 15000010; chars: 1871822228
Elapsed time: 165.704300ms

11 ! .


SIMD-


, , SSE AVX . 32 AVX/AVX2:


void word_count_avx( unsigned char* const str, uint32_t size, stats& result )
{
    uint32_t lines = 1;
    uint32_t words = 0;

    bool was_space = false;

    for ( uint32_t i = 0; i < size; i += 32 )
    {
        _mm_prefetch( (char*)str + i + 32 * 64, _MM_HINT_NTA );

        __m256i const c = _mm256_load_si256( (__m256i*)( str + i ) );
        uint32_t is_newline_mask = _mm256_movemask_epi8(
            _mm256_cmpeq_epi8( c, _mm256_set1_epi8( '\n' ) )
        );

        uint32_t is_space_mask = _mm256_movemask_epi8(
            _mm256_andnot_si256( c, _mm256_sub_epi8( c, _mm256_set1_epi8( ' ' + 1 ) ) )
        );
        uint32_t was_space_mask = ( was_space ? 1 : 0 ) | ( is_space_mask << 1 );

        lines += __popcnt( is_newline_mask );
        words += __popcnt( is_space_mask & ~was_space_mask );
        was_space = is_space_mask & 0x80000000;
    }

    words += !was_space ? 1 : 0;

    result.char_count = size;
    result.line_count = lines;
    result.word_count = words;
}

, SSE- . AVX/AVX2, , . 16, 32, 32-.


:


Words: 44774640; lines: 15000010; chars: 1871822228
Elapsed time: 109.606000ms

.


Prefetch


, , , , , _mm_prefetch. , , (, , ). AVX-:


void word_count2( unsigned char* const str, uint32_t size, stats& result )
{
    // ..............

    for ( uint32_t i = 0; i < size; i += 32 )
    {
        _mm_prefetch( (char*)str + i + 32 * 64, _MM_HINT_NTA );

        // ..............
    }

    // ..............
}

Words: 44774640; lines: 15000010; chars: 1871822228
Elapsed time: 73.564900ms

, 64 . , ; .


, RAM. тАФ , 70ms. ( ).



, , . , , , 1.8 Gb 10 .


рдХрд┐рд╕реА рднреА рдорд╛рдорд▓реЗ рдореЗрдВ, рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рд▓реЗрдЦ рджрд┐рд▓рдЪрд╕реНрдк рдерд╛, рдФрд░ рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рдЦреБрдж рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдирдпрд╛ рд╕реАрдЦ рд╕рдХрддрд╛ рд╣реИред


рд╣реЛрд▓реА рдХреА рд╢реБрднрдХрд╛рдордирд╛рдПрдБ!


All Articles