The Q6600
Benchmarks Game

fannkuch-redux PHP #3 program

source code

<?php 
/* The Computer Language Benchmarks Game
   https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
   
   multicore version 
   algorithm is based on Java 6 source code by Oleg Mazurov
   fork/shared mem is based on mandelbrot.php-3 
   contributed by Oleksii Prudkyi
*/

$n = (int) $argv[1];
$count_base = array();
$p_base = range(0, $n - 1);

$procs = 1;
if (file_exists('/proc/cpuinfo')) {
  $procs = preg_match_all('/^processor\s/m', file_get_contents('/proc/cpuinfo'), $discard);
}
$procs <<= 1;

$Fact = array(1);
for ($i = 1, $j = 0; $i <= $n; $j = $i++) {
   $Fact[$i] = $Fact[$j] * $i;
}

$index = 0;
$index_max = $Fact[$n];
$index_step = intval(($index_max + $procs-1) / $procs);

$shsize = $procs * 16;
$shmop = shmop_open(ftok(__FILE__, chr(time() & 255)), 'c', 0644, $shsize);

if (!$shmop) {
   echo "faild to shmop_open()\n";
   exit(1);
}

for ($proc = 0; $proc < $procs; ++$proc, $index += $index_step ) {
   
   if($proc < $procs - 1) {
      $pid = pcntl_fork();
      if ($pid === -1) {
         die('could not fork');
      } else if ($pid) {
         continue;
      }
   }

   $idxMin = $index;
   $idxMax = min( $index_max, $index + $index_step );

   //firstPermutation( idxMin );
   $count = $count_base;
   $p = $p_base;
   $idx = $idxMin;
   for ($i = $n - 1; $i > 0; --$i ) {
      $factI = $Fact[$i];
      $reminder = $idx % $factI;
      $d = (($idx- $reminder) / $factI);
      $count[$i] = $d;
      $idx = $reminder;

      $pp = $p;
      for ($j=0, $jd = $d; $j<=$i; ++$j, ++$jd ) {
         $p[$j] = $pp[($jd <= $i) ? $jd :$jd-$i-1];
      }
   }

   $maxflips = 1;
   $chksum = 0;
   $sign = 1;
   for ($idx =$idxMin;; ) {

      $first = $p[0];
      if ( $first != 0 ) {
         //int flips = countFlips();
         $flips = 1;
         if ( $p[$first] != 0 ) {
            $pp = $p;
            $p0 = $first;
            do {
               ++$flips;
               if ($p0 >= 3){
                  $i = 1; $j = $p0 - 1;
                  do { 
                     $t = $pp[$i]; 
                     $pp[$i] = $pp[$j]; 
                     $pp[$j] = $t; 
                     ++$i;
                     --$j;
                  } while ($i < $j); 
               }

               $t = $pp[$p0];
               $pp[$p0] = $p0;
               $p0 = $t;
            } while ( $pp[$p0] != 0 );
         }
         $maxflips = max( $maxflips, $flips );
         $chksum += $sign*$flips;
      }

      ++$idx ;
      if ( $idx  == ($idxMax) ) {
         break;
      }

      if ($sign == 1){
         $p[0] = $p[1];
         $p[1] = $first;
         $sign = -1;
      } else {
         $t = $p[1]; 
         $p[1] = $p[2]; 
         $p[2] = $t; 
         $sign = 1; 
         
         for($i=2;;){ 
            $sx = &$count[$i];
            ++$sx;
            if ($sx <= $i) {
               break; 
            } else {
               $sx = 0;
               for($j=0; $j<=$i; ){ $p[$j++] = $p[$j]; } 
               ++$i;
               $p[$i] = $first;
               $first = $p[0]; 
            }
         }
      }
   }
   $written_size = shmop_write($shmop, pack("ii", $maxflips, $chksum), $proc * 16);

   if($pid === 0) {
      exit(0);
   }
}

$child = $procs - 1;
$status = 0;
while ($child-- > 0) {
   pcntl_wait($status);
}

$offset = 0;
$res = 0;
$chk = 0;
for ($proc = 0; $proc < $procs; ++$proc, $offset += 16 ) {
   list($v, $chk_v) = array_values(unpack('ia/ib', shmop_read($shmop, $offset, $written_size)));
   $res = max( $res, $v );
   $chk += $chk_v;
}

printf("%d\nPfannkuchen(%d) = %d\n", $chk, $n, $res);

    

notes, command-line, and program output

NOTES:
64-bit Ubuntu quad core
PHP 7.4.5 (cli) (built: May 11 2020 13:25:48) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies


Mon, 11 May 2020 21:19:51 GMT

COMMAND LINE:
/opt/src/php-7.4.5/bin/php -n  fannkuchredux.php-3.php 12

PROGRAM OUTPUT:
3968050
Pfannkuchen(12) = 65