Bit-Set

 view release on metacpan or  search on metacpan

lib/Bit/Set.pm  view on Meta::CPAN

A slightly more complex example, in which we create a bitset, set a few bits,
 extract them into a buffer (allocated via L<FFI::Platypus::Buffer|https://metacpan.org/pod/FFI::Platypus::Buffer>, though other
 possibilities exist e.g. through L<Task::MemManager|https://metacpan.org/pod/Task::MemManager>) and then checking that their
 values is correct. The load example logic is as follows: first, we allocate the
 buffer, then we set its value using pack, and finaly we put the buffer into a bitset and test the  individual bits.

    use Test::More; # Convenient testing framework
    use Bit::Set     qw(:all);
    use FFI::Platypus::Buffer;    

    use constant SIZE_OF_TEST_BIT => 65536;
    my $bitset = Bit_new(SIZE_OF_TEST_BIT);
    Bit_bset( $bitset, 2 );
    Bit_bset( $bitset, 0 );

    my $buffer_size = Bit_buffer_size(SIZE_OF_TEST_BIT);
    my $scalar =
      "\0" x $buffer_size;    
    my ( $buffer, $size ) =
      scalar_to_buffer $scalar;    
    my $bytes =
      Bit_extract( $bitset, $buffer );   

    my $first_byte = unpack( 'C', substr( $scalar, 0, 1 ) );
    is( $first_byte, 0b00000101, 'Bit_extract produces correct buffer' );
    Bit_free( \$bitset );

    # test_bit_load
    $scalar =
      "\0" x $buffer_size;    
    ( $buffer, $size ) =
      scalar_to_buffer $scalar;    

    substr( $scalar, 0, 1 ) = pack( 'C', 0b00000101 );
    $bitset = Bit_load( SIZE_OF_TEST_BIT, $buffer );

    my $load_success =
      ( Bit_get( $bitset, 0 ) == 1 && Bit_get( $bitset, 2 ) == 1 );
    ok( $load_success, 'Bit_load creates bitset from buffer correctly' );
    Bit_free( \$bitset );

=item Example 6: Benchmarking of the Perl interface to the Bit library

This example re-implements part of the C benchmarking suite for the Bit library
(found in the source file "benchmark.c" in the L<github repository for Bit|https://github.com/chrisarg/Bit>). The goal is to compare the performance of various bitset operations in Perl with their C counterparts, while showing a larger application th...
In this example we profile the time it takes to execute the intersection and the
count of the two intersection of two bitsets with variable capacity, ranging from 128 to 1048576 bits. The intersection and the count of the intersection is executed 1000 times and the time it takes to finish this benchmark is used to infer the perfo...
There is negligible overhead introduced by the Perl interface, making it a viable option for performance-critical applications, without the "pain" of writing an application in C.
The github repo L<benchmarking-bits|https://github.com/chrisarg/benchmarking-bits> contains an extensive benchmarking suite that compares the performance of the FFI and XS implementations of both the procedural and the OO interfaces of the Bit::Set m...

    use strict;
    use warnings;
    use Time::HiRes  qw(gettimeofday tv_interval);
    use Bit::Set     qw(:all);

    # Constants
    use constant BPQW => 64;    # bits per qword (8 bytes * 8 bits)
    use constant BPB  => 8;     # bits per byte


    # Test sizes and iterations
    my @size_array = (
        128,   256,   512,    1024,   2048,   4096, 8192, 16384,
        32768, 65536, 131072, 262144, 524288, 1048576
    );
    my $iterations = 1000;

    # Benchmark function registry
    my %benchmark_funcs = (
        'Count' => {
            code  => \&benchmark_bit_count,
            descr => 'Count the number of bits set in the bitset'
        },
        'Inter Count' => {
            code  => \&benchmark_bit_inter_count,
            descr => 'Count the number of bits set in an intersection'
        },
    );

    print "Benchmarking the Perl Bit::Set library\n";
    print "=" x 50, "\n";
    for my $test ( sort keys %benchmark_funcs ) {
        printf "%-15s => %s\n", $test, $benchmark_funcs{$test}{descr};
    }
    print "\n";



    # Benchmark functions for each test type
    sub benchmark_bit_count {
        my ($size) = @_;

        # Pre-create bitsets outside the benchmark
        my $bit1 = Bit_new($size);
        Bit_set( $bit1, int( $size / 2 ), $size - 1 );
        Bit_bset( $bit1, 0 );

        my $t0         = [gettimeofday];
        my $result     = Bit_count($bit1) for 1 .. $iterations;
        my $t1         = [gettimeofday];
        my $total_time = tv_interval $t0, $t1;

        Bit_free( \$bit1 );

        return $total_time;
    }

    sub benchmark_bit_inter_count {
        my ($size) = @_;

        # Pre-create bitsets outside the benchmark
        my $bit1 = Bit_new($size);
        my $bit2 = Bit_new($size);
        Bit_set( $bit1, int( $size / 2 ), $size - 1 );
        Bit_bset( $bit1, 0 );

        my $t0         = [gettimeofday];
        my $result     = Bit_inter_count( $bit1, $bit2 ) for 1 .. $iterations;
        my $t1         = [gettimeofday];
        my $total_time = tv_interval $t0, $t1;

        Bit_free( \$bit1 );
        Bit_free( \$bit2 );

        return $total_time;

    }

    sub run_benchmark {
        my ( $test_name, $size, $benchmark_func ) = @_;

        my $total_time = $benchmark_func->($size);

        my $total_time_ns = $total_time * 1_000_000_000;    # Convert to nanoseconds

        # Calculate derived metrics
        my $time_per_iteration    = $total_time_ns / $iterations;
        my $iterations_per_second = $iterations / $total_time;

        # Format and print results
        printf
        "%-30s (size = %8d): %12.0f ns total\t%8.2f ns/iter\t%10.2e iter/s\n",
        "Bit $test_name", $size, $total_time_ns, $time_per_iteration,
        $iterations_per_second;
    }

    # Main benchmark execution
    print "Running individual benchmarks...\n";
    print "=" x 80, "\n";

    for my $test_name ( sort keys %benchmark_funcs ) {
        print "\nBenchmarking $test_name: $benchmark_funcs{$test_name}{descr}\n";
        print "-" x 80, "\n";
        for my $size (@size_array) {
            run_benchmark( $test_name, $size, $benchmark_funcs{$test_name}{code} );
        }

    }

    print "\n\nBenchmark completed!\n";

=back


=head1 SEE ALSO

=over 4

=item L<Alien::Bit|https://metacpan.org/pod/Alien::Bit>

This distribution provides the library Bit so that it can be used by other Perl 
distributions that are on CPAN. It will download Bit from Github and will build 
the (static and dynamic) versions of the library for use by other Perl modules.

=item L<benchmarking-bits|https://github.com/chrisarg/benchmarking-bits>

A collection of benchmarking scripts for various bitset libraries in C and Perl.

=item L<Bit|https://github.com/chrisarg/Bit>

Bit is a high-performance, uncompressed bitset implementation in C, optimized 
for modern architectures. The library provides an efficient way to create, 
manipulate, and query bitsets with a focus on performance and memory alignment. 
The API and the interface is largely based on David Hanson's Bit_T library 
discussed in Chapter 13 of "C Interfaces and Implementations", 
Addison-Wesley ISBN 0-201-49841-3 extended to incorporate additional operations 
(such as counts on unions/differences/intersections of sets), 
fast population counts using the libpocnt library and GPU operations for packed 
containers of (collections) of Bit(sets).

=item L<Bit::Set::OO|https://metacpan.org/pod/Bit::Set::OO>

Object Oriented interface to the Bit::Set module.

=item L<Bit::Set::DB|https://metacpan.org/pod/Bit::Set::DB>

Procedural interface to the containerized operations of the Bit library.

=item L<Bit::Set::DB::OO|https://metacpan.org/pod/Bit::Set::DB::OO>

Object Oriented interface to the Bit::Set::DB module.

=item L<Bit::Vector|https://metacpan.org/pod/Bit::Vector>



( run in 2.021 seconds using v1.01-cache-2.11-cpan-96521ef73a4 )