Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
Those are quite strong words for a post that includes no benchmarks. I put together three small test programs, one using MySQL, another using SysV semaphores and shared memory, and another using mmap and a gcc-specific atomic_add operation. On the machine where I ran the code MySQL could increment a counter in a MyISAM table about 2200 times/second, or in a memory table about 3500 times/second. Using SysV IPC, I could increment about 15,540 times/second, not quite 5 times faster than the memory table. Using mmap and system-specific atomic locking instructions from C++, I can increment about 9.6 million times/second, which is about 2700 times faster than a MySQL memory table. With 3 writers, MySQL and SysV take about 3 times as long for all 3 to finish, so they are serialized but not penalized too badly for the lock contention; the mmap+atomic_add version actually gets faster (12.2M times/second), because it can run on two processors at the same time. So there are definitely performance advantages to doing a bit of the work yourself.

Now, if the OP's question hadn't been about performance, that probably wouldn't matter; you're right that SysV IPC is rarely used, and the MySQL code is much easier to understand and maintain. But his question was in fact about performance, and in a later post dino states specifically that the performance of MySQL was not fast enough, so advising him to use it is particularly unhelpful. Also, there are certainly more modern forms of IPC, but none that have builtin support in Perl.

Here is the code I used. If you have anything faster, please post it along with benchmarks.

Update: Fixed some errors in benchmarks (there was no row in MySQL, so the UPDATE statements weren't doing anything. Added another test with mmap+atomic_add. Fixed a typo.

counter1.pl, with SysV IPC
#!/usr/bin/perl use warnings; use strict; use IPC::SysV qw(IPC_CREAT ftok SEM_UNDO); use IPC::Semaphore; my $semtok = ftok($0,1); my $shmtok = ftok($0,2); my $sem = IPC::Semaphore->new($semtok, 1, 0700 | IPC_CREAT) or die "Couldn't create semaphore: $!\n"; my $shmid = shmget($shmtok,4,0700 | IPC_CREAT) or die "Couldn't create shm: $!\n"; if ($ENV{RESET}) { $sem->setval(0,0); my $buf = pack("L",0); shmwrite($shmid, $buf, 0, 4) or die "shmwrite failed: $!\n"; if (!$ARGV[0]) { exit(0); } } foreach my $i(1..$ARGV[0]||100) { my $r = add(1); if ($ENV{VERBOSE}) { print $r,"\n"; } } sub add { my($add) = @_; # Lock: wait for 0, then semaphore up $sem->op(0, 0, 0, 0, 1, 0) or die "semaphore lock failed: $!\n"; # Read counter my $buf; shmread($shmid, $buf, 0, 4) or die "shmread failed: $!\n"; my $val = unpack("L",$buf); # Increment $val += $add; # Write it back $buf = pack("L",$val); shmwrite($shmid, $buf, 0, 4) or die "shmwrite failed: $!\n"; # Now unlock; semaphore down $sem->op(0, -1, 0) or die "semaphore unlock failed: $!\n"; return $val; }
counter2.pl, with MySQL. Use CREATE TABLE counter (count int); to create the table, then INSERT INTO counter VALUES (0); to put a value in it.
#!/usr/bin/perl use warnings; use strict; use DBI; our $dbh = DBI->connect('DBI:mysql:database=test','db_user','db_pass') or die "Couldn't connect to db\n"; our $sth = $dbh->prepare("UPDATE counter SET count = count + ?") or die "Couldn't prepare statement\n"; foreach my $i(1..$ARGV[0]||100) { my $r = add(1); } sub add { $sth->execute($_[0]) or die "Couldn't to SQL: $!\n"; }
counter3.C, mmap and atomic_add in C++ (with a little work could be done in Perl/C++ hybrid with Inline::CPP)
#include <sys/mman.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream> #include <bits/atomicity.h> using __gnu_cxx::__atomic_add; using __gnu_cxx::__exchange_and_add; using namespace std; void die(char *msg) { perror(msg); exit(0); } void add(volatile _Atomic_word *to, int amt) { __atomic_add(to, amt); } int main(int argc, char *argv[]) { if (argc < 2) { die("bad usage"); } int mmap_fd = open(argv[1], O_RDWR); if (mmap_fd < 0) die("couldn't open mmap"); void *mem = mmap(NULL, sizeof(_Atomic_word), PROT_WRITE, MAP_SHARED, + mmap_fd, 0); if (mem == NULL) die("couldn't mmap file"); volatile _Atomic_word *counter = (volatile _Atomic_word *)mem; int count = atoi(argv[2]); for(int i=0;i<count;i++) { add(counter, 1); } cout << "counter is now " << *counter << endl; }

In reply to Re^3: Multiple write locking for BerkeleyDB by sgifford
in thread Multiple write locking for BerkeleyDB by dino

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (4)
As of 2023-09-25 09:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?