新規作成
OpenIDで認証してエントリーを新規作成します
共有
エントリーにはOpenIDで閲覧と編集に制限かけることができます
変更履歴
編集履歴もあるので、コラボレーションにも活用できます

memcached 1.3.3のgrow_stats_bufのpatch

statsでセグフォる件

--- memcached-1.3.3.orig/memcached.c    2009-04-06 18:24:53.000000000 +0900
+++ memcached-1.3.3/memcached.c 2009-04-06 19:00:39.000000000 +0900
@@ -1335,15 +1335,14 @@
 }
 
 static bool grow_stats_buf(conn *c, size_t needed) {
-    size_t size = c->stats.size - c->stats.offset;
-    size_t nsize = size;
+    size_t nsize = c->stats.size;
     bool rv = true;
 
-    while (nsize < needed) {
-        nsize = nsize << 1;
+    while (nsize < needed + c->stats.offset) {
+        nsize = nsize + 2048;
     }
 
-    if (nsize > size) {
+    if (nsize > c->stats.size) {
         char *ptr = realloc(c->stats.buffer, nsize);
         if (ptr) {
             c->stats.buffer = ptr;
created by blog.nomadscafe.jp

Classメソッド読み出しの速度

まだ古めかしい世界です


classメソッドの読み出しはobjectのそれと比べて遅い

$ perl class.pl 
               Rate class_raw     class    object class_old
class_raw 1449275/s        --       -2%      -18%      -36%
class     1481481/s        2%        --      -16%      -35%
object    1769912/s       22%       19%        --      -22%
class_old 2272727/s       57%       53%       28%        --
$ perl -v
This is perl, v5.8.8 built for i386-linux-thread-multi
#!/usr/bin/perl

use strict;

package Hoge;

sub new { bless {}, shift }
sub hoge { '1' }

package main;

use Benchmark;

my $object = Hoge->new;
my $class = 'Hoge';

Benchmark::cmpthese(2000000, {
    'class' => sub { $class->hoge },
    'class_raw' => sub { Hoge->hoge },
    'class_old' => sub { Hoge::hoge() },
    'object' => sub { $object->hoge },
});
created by blog.nomadscafe.jp

TokyoTyrant.pmてすと

Tokyo Tyrantのperlクライアントがでているので、軽くベンチとってみた


Tokyo Tyrantは

$ ttserver

だけで起動。on memoryのhash dbになりますね


このサーバに対して、Cache::Memcached、同Fast、TokyoTyrant.pmで接続してgetの速度を比較してみた

バージョンは

Tokyo Tyrant 1.1.11
tokyotyrant-perl 1.4
Cache::Memcached 1.21
Cache::Memcached::Fast 0.08

先に結果

$ perl tt_bench.pl
                    Rate cache::memcached      tokyotyrant             fast
cache::memcached  7168/s               --             -68%             -82%
tokyotyrant      22222/s             210%               --             -46%
fast             40816/s             469%              84%               --

TokyoTyrant.pmはなかなか速い

独自プロトコルで通信できるからですかねぇ


ベンチマークスクリプト

use strict;
use warnings;
use Cache::Memcached::Fast;
use Cache::Memcached;
use TokyoTyrant;
use Benchmark qw/cmpthese/;

my $n = 20000;
my $key = "foo";

my $fast = Cache::Memcached::Fast->new( { servers => ['127.0.0.1:1978'] } );
$fast->set( $key => rand );

my $pp = Cache::Memcached->new( { servers => ['127.0.0.1:1978'] } );

my $tt = TokyoTyrant::RDB->new();
$tt->open("localhost", 1978);

cmpthese(
    $n => {
        tokyotyrant => sub {
            $tt->get($key);
        },
        fast => sub {
            $fast->get($key);
        },
        'cache::memcached' => sub {
            $pp->get($key);
        },
    }
);
created by blog.nomadscafe.jp

CPAN search - index.html

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
      <head>
               <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
               <title>CPAN</title>
               <link rel="stylesheet" type="text/css" href="reset.css" />
               <link rel="stylesheet" type="text/css" href="fonts.css" />
               <style type="text/css">

#view {
      border: none;
      width: 100%;
}

#dialog {
      position: absolute;
      z-index: 98;
      top: 0px;
      left: 0px;
      border: solid 2px #7ae;
      width: 20em;
}

#dialog h1 {
      padding: 2px 0px 4px 4px;
      background-color: #7ae;
      cursor: pointer;
      font-size: 77%;
      font-weight: bold;
}

#message {
      background-color: #fff;
}

#search {
      width: 97%;
      ime-mode: disabled;
}

#modules li {
      display: block;
      padding: 3px;
      border-top: solid 1px #ccc;
      background-color: #fff;
      cursor: pointer;
}

#modules.highlight li:hover {
      background-color: #eef;
}

#modules li.focused,
#modules.highlight li:hover.focused {
      color: #fff;
      background-color: #339;
}

              </style>
               <script type="text/javascript" src="jquery-1.2.6.min.js"></script>
               <script type="text/javascript" src="jquery.mousewheel.min.js"></script>
               <script type="text/javascript" src="vars.js"></script>
               <script type="text/javascript" src="main.js"></script>
       </head>
      <body>
              <div id="dialog">
                      <h1>CPAN Search</h1>
                      <div class="inner">
                              <p id="message"><p>
                              <input id="search" name="search" />
                              <ul id="modules">
                                      <li>&nbsp;</li>
                              </ul>
                      </div>
              </div>
              <iframe id="view"></iframe>
      </body>
</html>
created by http://www.hatena.ne.jp/dayflower/

CPAN search - main.js

$(function () {
////////////////////////////////////////////////////////////////////////

var use_iframe    = false;
var wheel_step    = 3;
var scroll_margin = 1;
var max_rows      = 25;
var page_size     = function () { return Math.ceil(rows / 2) };

////////////////////////////////////////////////////////////////////////

var MethodQueue = function () {
      this.ctor.apply(this, arguments);
};

MethodQueue.prototype = {
      ctor: function () {
              var args = arguments[0];
              this.timeout     = args.timeout     || 1000;
              this.latest_only = args.latest_only;

              this.fns      = [];
              this.timer_id = null;
      },

      clear: function () {
              this.fns = [];
      },

      append: function (fn) {
              if (this.timer_id) {
                      clearTimeout(this.timer_id);
                      this.timer_id = null;
              }

              if (this.latest_only)
                      this.fns = [ fn ];
              else
                      this.fns[this.fns.length] = fn;

              var self = this;
              this.timer_id
                      = setTimeout(function () { self._execute(); }, this.timeout);
      },

      _execute: function () {
              for (var i = 0; i < this.fns.length; i ++)
                      this.fns[i].apply(this);

              this.clear();
      }
};

////////////////////////////////////////////////////////////////////////

var modules;
var candidates = [];
var cursor     = 0;
var offset     = 0;
var rows       = (max_rows > 0) ? max_rows : 25;
var loaded     = false;
var searched   = false;
var last_word  = '';
var moved      = false;
var collapsed  = false;
var row_height = 16;
var mods_top   = 0;

var mq = new MethodQueue({
      timeout:     200,
      latest_only: true
});

$('#message').text('loading ...');

function open_url(url, newwin) {
      if (newwin) {
              var w = window.open(
                      url, '_blank',
                      'location=yes,menubar=yes,toolbar=yes,directories=yes,'
                      + 'width=' + window.width + ',height=' + window.height);

              if (! w)
                      $('#message').text('popup is disabled.');
      }
      else {
              var v = document.getElementById('view');
              if (v && use_iframe) {
                      show_dialog(false);
                      v.src = url;
              }
              else {
                      window.location = url;
              }
      }
}

function open_module(newwin) {
      if (window.bundles_static) {
              for (var i = 0, n = bundles_static.length; i < n; i ++)
                      if (bundles_static[i] == candidates[cursor]) {
                              open_url(
                                      'http://perldoc.perl.org/' + bundles_static[i] + '.html',
                                      newwin);
                              return;
                      }
      }

      open_url('http://search.cpan.org/perldoc?' + candidates[cursor], newwin);
}

function render_candidates() {
      var n = candidates.length;

      var items = '';
      if (n > 0) {
              var c = cursor - offset;
              var r = candidates.length - offset;
              if (r > rows)
                      r = rows;

              var is = [];
              for (var i = 0; i < r; i ++)
                      is[i] = '<li id="module-' + (offset + i) + '">'
                            + candidates[offset + i]
                            + '</li>';

              if (c >= 0 && c < r) {
                      is[c] = '<li id="module-' + (offset + c) + '" class="focused">'
                            + candidates[offset + c]
                            + '</li>';
              }

              items = is.join('');
      }

      $('#modules').html(items);
}

function choose_candidates(w) {
      var cmp;
      if (w.match('[^:_0-9A-Za-z]')) {
              if (w.charAt(0) == '~')
                      w = w.substring(1);
              try {
                      var re = new RegExp(w, 'i');
                      cmp = function (m) { return m.match(re) };
              }
              catch (e) {
                      return;
              }
      }
      else {
              w = w.toLowerCase();
              var len = w.length;
              cmp = function (m) {
                      var s = m.substring(0, len) || '';
                      return s.toLowerCase() == w
              };
      }

      searched = false;

      cursor = offset = 0;
      candidates = [];

      if (len == 0) {
              candidates = modules;
      }
      else {
              for (var i = 0, n = modules.length; i < n; i ++) {
                      var m = modules[i];
                      if (m == undefined) continue;
                      if (cmp(m)) {
                              candidates[candidates.length] = m;
                      }
              }
      }

      searched = true;

      render_candidates();

      $('#message').text(candidates.length + ' modules selected.');
}

function check_search() {
      var e = $('#search');
      var w = e.val();
      if (w == last_word)
              return;
      last_word = w;

      mq.append(function () { choose_candidates(w) });
}

function make_mouse_moved(m) {
      if (moved == m)
              return;

      moved = m;

      if (moved)
              $('#modules').addClass('highlight');
      else
              $('#modules').removeClass('highlight');
}

function move_cursor(pos, force) {
      if (candidates.length <= 0)
              return;

      var off = offset;

      // scroll into view
      var c = pos - off;
      if (c < 0 + scroll_margin) {
              off = pos - 1;
              if (off < 0)
                      off = 0;
      }
      else if (c > rows - 1 - scroll_margin) {
              off = pos - rows + 1 + scroll_margin;
              if (off < 0)
                      off = 0;
              if (off == candidates.length - rows + scroll_margin)
                      off --;
      }

      if (! force && pos == cursor && off == offset)
              return;
      cursor = pos;
      offset = off;

      render_candidates();

      $('#message').text((cursor + 1) + ' / ' + candidates.length + ' modules');
}

function move_cursor_delta(delta) {
      var pos = Math.floor(cursor + delta);

      if (pos < 0)
              pos = 0;
      if (pos > candidates.length - 1)
              pos = candidates.length - 1;

      move_cursor(pos);
}

function move_cursor_by_key(key, ctrl, keydown) {
      if (! searched)
              return false;

      var f = true;

      switch (key) {
      case 13:    /* CR */
              f = false;
              open_module(ctrl);
              break;
      case 38:    /* UP */
              f = false;
              if (! keydown) {
                      move_cursor_delta(-1);
                      make_mouse_moved(false);
              }
              break;
      case 40:    /* DOWN */
              f = false;
              if (! keydown) {
                      move_cursor_delta(1);
                      make_mouse_moved(false);
              }
              break;
      case 33:    /* PAGEUP */
              f = false;
              if (! keydown) {
                      move_cursor_delta(- page_size());
                      make_mouse_moved(false);
              }
              break;
      case 34:    /* PAGEDOWN */
              f = false;
              if (! keydown) {
                      move_cursor_delta(page_size());
                      make_mouse_moved(false);
              }
              break;
      case 36:    /* HOME */
              if (ctrl) {
                      f = false;
                      if (keydown) {
                              move_cursor(0);
                              make_mouse_moved(false);
                      }
              }
              break;
      case 35:    /* END */
              if (ctrl) {
                      f = false;
                      if (keydown) {
                              move_cursor(candidates.length - 1);
                              make_mouse_moved(false);
                      }
              }
              break;

      default:
              break;
      }

      return f;
}

function on_resize() {
      var wh = $(window).height();

      document.getElementById('view').height = wh;

      if (! collapsed) {
              var e = document.getElementById('modules');
              mods_top = e.offsetTop;

              var rh;
              for (var c = e.firstChild; c; c = c.nextSibling) {
                      if (c.nodeType == 1) {
                              rh = c.offsetHeight;
                              break;
                      }
              }
              if (! rh)
                      rh = 16;
              row_height = rh;
      }

      var h = wh - 4 - mods_top;

      rows = Math.floor(h / row_height);
      if (max_rows > 0 && rows > max_rows)
              rows = max_rows;

      // recalculate
      move_cursor(cursor, true);

      return true;
}

function show_dialog(show) {
      if (collapsed == ! show)
              return;

      if (show) {
              $('#dialog .inner').slideDown(
                      'fast',
                      function () {
                              collapsed = false;
                      });
      }
      else {
              $('#dialog .inner').slideUp(
                      'fast',
                      function () {
                              collapsed = true;
                      });
      }
}

function show_dialog_toggle() {
      show_dialog(collapsed);
}

$(window).resize(on_resize);
on_resize();

$('#search')
      .keydown(function (e) {
              // ignore whitespace
              if (e.which == 32)
                      return false;
              if (! loaded)
                      return true;

              if (e.which <= 48) {
                      return move_cursor_by_key(e.which, e.ctrlKey, true);
              }
              else {
                      setTimeout(check_search, 0);
                      return true;
              }
      })
      .keypress(function (e) {
              // ignore whitespace
              if (e.which == 32)
                      return false;
              if (! loaded)
                      return true;

              if (e.which == 0 && e.keyCode <= 48) {
                      return move_cursor_by_key(e.keyCode, e.ctrlKey, false);
              }
              else {
                      setTimeout(check_search, 0);
                      return true;
              }
      });

$('#modules')
      .click(function (ev) {
              e = ev.originalTarget || ev.srcElement;
              if (e.nodeName == "LI") {
                      // 7 is magical, length of "module-"
                      var c = parseInt(e.id.substring(7));

                      if (c == cursor) {  // double click
                              open_module(ev.ctrlKey);
                              return false;
                      }
                      else {
                              cursor = c;
                              render_candidates();
                              document.getElementById('search').focus();
                              return false;
                      }
              }

              return true;
      })
      .mousemove(function (e) {
              make_mouse_moved(true);
              return true;
      })
      .mousewheel(function (e, delta) {
              move_cursor_delta(-delta * wheel_step);
              document.getElementById('search').focus();
              return false;
      });

$('#dialog h1').click(show_dialog_toggle);

if (window.packages_static) {
      setTimeout(
              function () {
                      modules = packages_static.concat(bundles_static);
                      packages_static = [];
                      $('#message').text(modules.length + ' modules loaded.');
                      loaded = true;
                      choose_candidates('');
              },
              0);
}
else {
      $.getJSON(
              "packages.js",
              function (pkgs) {
                      $.getJSON(
                              "bundles.js",
                              function (bnds) {
                                      modules = pkgs.concat(bnds);
                                      $('#message').text(modules.length + ' modules loaded.');
                                      loaded = true;
                                      choose_candidates('');
                              })
              });
}

(function () {
      var e = document.getElementById('view');
      if (e)
              e.src = '';

      e = document.getElementById('search');
      e.value = '';
      e.focus();
})();

////////////////////////////////////////////////////////////////////////
});
created by http://www.hatena.ne.jp/dayflower/

64bit環境でのmemory-shell.plの結果

ライブラリのメモリ使用状況を手軽にしらべられるツールかいた

FedoraCore6 x86_64での結果

$ perl memory-shell.pl 
perl> use DBI
3,698,688
perl> use Storable
4,554,752
perl> use Data::Dumper
2,535,424
perl> use Cache::Memcached  
18,837,504
perl> use Cache::Memcached::Fast
6,856,704

tokuhiromの結果と結構違うなー

created by blog.nomadscafe.jp

小数点n桁

intの方がはやい

Benchmark: timing 2000000 iterations of int, sprintf...
       int:  1 wallclock secs ( 0.65 usr +  0.00 sys =  0.65 CPU) @ 3076923.08/s (n=2000000)
   sprintf:  5 wallclock secs ( 5.42 usr +  0.00 sys =  5.42 CPU) @ 369003.69/s (n=2000000)
use strict;
use Time::HiRes qw//;
use Benchmark;

my $time = Time::HiRes::time();

Benchmark::timethese(2000000, {
    'sprintf' => sub { sprintf "%.2f", $time },
    'int' => sub { int($time*100)/100 },
});
created by blog.nomadscafe.jp

DoCoMo::Displayの新機種への対応

Index: t/03_docomo_displaymap.t
===================================================================
--- t/03_docomo_displaymap.t    (revision 24544)
+++ t/03_docomo_displaymap.t    (working copy)
@@ -1,9 +1,9 @@
 use strict;
 use warnings;
-use Test::More tests => 2;
+use Test::More tests => 3;
 use WWW::MobileCarrierJP::DoCoMo::Display;
 
 my $dat = WWW::MobileCarrierJP::DoCoMo::Display->scrape;
 ok scalar(@$dat) > 30;
 is scalar(grep { $_->{model} eq 'D905i' } @$dat), 1;
-
+is scalar(grep { $_->{model} eq 'F-01A' } @$dat), 1;
Index: lib/WWW/MobileCarrierJP/DoCoMo/Display.pm
===================================================================
--- lib/WWW/MobileCarrierJP/DoCoMo/Display.pm   (revision 24544)
+++ lib/WWW/MobileCarrierJP/DoCoMo/Display.pm   (working copy)
@@ -42,7 +42,7 @@
 
 sub _regexp {
     return <<'RE';
-<td><span class="txt">([A-Z]+\d+\w*\+?).*?</span></td>
+<td(?: colspan="2")?><span class="txt">([A-Z]+-?\d+\w*\+?).*?</span></td>
 <td><span class="txt">.*?(?:</span></td>)?
 <td><span class="txt">.*?(?:</span></td>)?
 <td><span class="txt">.*?(\d+)×(\d+).*?</span></td>

http://coderepos.org/share/changeset/24546 commitした

created by blog.nomadscafe.jp

http://www.hatena.ne.jp/mickys0715/

created by http://www.hatena.ne.jp/mickys0715/

proxymapper.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>

#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX   108
#endif

const int  TIMEOUT       = 3;
const char SOCKET_PATH[] = "/tmp/proxymapper";

static int sd;
static int ast = 0;

static void
force_close_socket()
{
    if (sd)
        close(sd);
    sd = 0;
}

static void
alarm_handler(int signum)
{
    if (ast < 0)
        force_close_socket();
}

static int
connect_socket(void)
{
    struct sockaddr_un addr;
    /* int sd; */       /* here I use global sd */

    bzero((char *) &addr, sizeof(addr));
    addr.sun_family = AF_UNIX;
    if (strlen(SOCKET_PATH) >= UNIX_PATH_MAX-1) {
        exit(1);
    }
    strncpy(addr.sun_path, SOCKET_PATH, UNIX_PATH_MAX-1);

    sd = socket(PF_UNIX, SOCK_STREAM, 0);
    if (sd < 0) {
        perror("socket");
        exit(1);
    }

    if (connect(sd, (struct sockaddr *) &addr,
                sizeof(addr.sun_family) + strlen(addr.sun_path)) < 0) {
        /* perror("connect"); */
        return 0;
    }

    return sd;
}

static FILE *
connect_to_remote(void)
{
    int sd;
    FILE *sp;

    sd = connect_socket();
    if (sd <= 0)
        return NULL;

    sp = fdopen(sd, "r+");
    if (sp == NULL) {
        /* perror("fdopen"); */
        force_close_socket();
        return NULL;
    }

    if (setvbuf(sp, NULL, _IONBF, 0) != 0) {
        /* perror("setvbuf"); */
        fclose(sp);
        force_close_socket();
        return NULL;
    }

    return sp;
}

static char buffer[1024];

static const char *
comm_with_remote(FILE *sp, const char *message)
{
    ast = -1;
    alarm(TIMEOUT);
    ast = (fputs(message, sp) < 0);
    alarm(0);
    if (ast)
        return NULL;

    ast = -1;
    alarm(TIMEOUT);
    ast = (fgets(buffer, sizeof(buffer), sp) == NULL);
    alarm(0);
    if (ast)
        return NULL;

    if (strlen(buffer) == 0 || buffer[strlen(buffer) - 1] != '\n') {
        force_close_socket();
        return NULL;
    }

    return buffer;
}

int
main(int argc, char *argv[])
{
    FILE *sp = NULL;

    signal(SIGPIPE, SIG_IGN);
    signal(SIGALRM, alarm_handler);

    /* set stdout to unbuffered mode */
    if (setvbuf(stdout, NULL, _IONBF, 0) != 0) {
        perror("setvbuf");
        exit(1);
    }

    while (fgets(buffer, sizeof(buffer), stdin)) {
        if (strlen(buffer) == 0)
            continue;
        if (buffer[strlen(buffer) - 1] != '\n') {
            /* continuous => slurp, and error */
            while (fgets(buffer, sizeof(buffer), stdin)) {
                if (strlen(buffer) == 0)
                    continue;
                if (buffer[strlen(buffer) - 1] == '\n')
                    break;
            }

            fputs("NULL\n", stdout);
            continue;
        }

        if (! sp) {
            sp = connect_to_remote();

            if (! sp) {
                fputs("NULL\n", stdout);
                continue;
            }

            if (comm_with_remote(sp, buffer) == NULL) {
                /* unrecoverable error */
                fputs("NULL\n", stdout);
                continue;
            }
        }
        else {
            if (comm_with_remote(sp, buffer) == NULL) {
                /* reopen */
                sp = connect_to_remote();

                if (! sp) {
                    fputs("NULL\n", stdout);
                    continue;
                }

                /* 2nd try */
                if (comm_with_remote(sp, buffer) == NULL) {
                    /* unrecoverable error */
                    fputs("NULL\n", stdout);
                    continue;
                }
            }
        }

        fputs(buffer, stdout);
    }

    if (sp) {
        fclose(sp);
        force_close_socket();
    }

    return 0;
}
created by http://www.hatena.ne.jp/dayflower/

<3456789101112>