caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Chris Hecker <checker@d6.com>
To: eijiro_sumii@anet.ne.jp, caml-list@inria.fr
Cc: gerd@gerd-stolpmann.de, sumii@venus.is.s.u-tokyo.ac.jp
Subject: Re: substring match like "strstr"
Date: Mon, 11 Dec 2000 13:07:22 -0800	[thread overview]
Message-ID: <4.3.2.7.2.20001211103237.00c12100@shell16.ba.best.com> (raw)
In-Reply-To: <20001210221657W.sumii@yl.is.s.u-tokyo.ac.jp>


>The results (execution time in seconds) were as follows.
>  strstr   55.74
>  regexp  154.37
>  OCamlA  302.57
>  OCamlB  129.23

Any ideas why strstr blows the others away?  What's the libc strstr look like?  I just looked in the MSVC source and it's a braindead while loop (copied below), so it's not like it's doing a fancy Boyer-Moore or anything.  This is exactly the kind of problem on which I'd expect caml to come within 10% of c.

Have you tried a purely imperative version?  I'd say I'd do the tests myself, but I don't have a bunch of gene sequences laying around.  :)  

Okay, I'm curious, so I'll port the code to caml and include it below as well (as practice for myself).  Can you try it in your test harness?  I've attached a cheesy test app with your caml, calling msvc's strstr, and my imperative version.  I make no claims of profiling accuracy or even code correctness, but here are the results when run from a DOS box on Win98:

strstr total = 1.060000 (5,0,19,13)
strstr_imp total = 0.510000 (5,0,19,13)
strstr_c total = 0.415000 (5,0,19,13)

(The weird thing is when I ran it with shell-command under emacs the timings were 

strstr total = 0.575000 (5,0,19,13)
strstr_imp total = 0.500000 (5,0,19,13)
strstr_c total = 0.415000 (5,0,19,13)

which I found bizarre since strstr became 2x faster, but I haven't had time to look into it.  Can somebody else try these tests? )

Looking at the asm output from strstr_imp, there's not that much you could do to make it better.  Maybe there are a few peephole things, and there are probably 30% more instructions than you need in this specific case because the code to compare characters goes to the trouble of keeping the ints in the caml format even in registers inside the loop (so they're shifted back and forth), and it converts the chars from the unsafe_gets to full caml ints, which is useless since they just get compared to each other and then dumped.  It might be interesting to write a peephole optimizer aimed at peepholing camlopt code, and looking for things like this.

Can anybody optimize the caml src for strstr_imp?

Chris


----strstrc.c-----


#include "/test/ocaml/lib/caml/mlvalues.h"

/* ripped from msvc crt src */
char * __cdecl strstr (
        const char * str1,
        const char * str2
        )
{
        char *cp = (char *) str1;
        char *s1, *s2;

        if ( !*str2 )
            return((char *)str1);

        while (*cp)
        {
                s1 = cp;
                s2 = (char *) str2;

                while ( *s1 && *s2 && !(*s1-*s2) )
                        s1++, s2++;

                if (!*s2)
                        return(cp);

                cp++;
        }

        return(0);

}

value Camlstrstr( value pat, value str )
{
    char *string = String_val(str);
    return Val_int(strstr(string,String_val(pat))-string);
}

------strstrc.mli-----


external strstr_c: string -> string -> int = "Camlstrstr"

------strstr.ml-------




(* Eijiro Sumii's functional strstr *)
let strstr pat str =
  let patlen = String.length pat in
  let strlen = String.length str in
  let rec is_prefix pos spos epos =
    if pos < 0 then true else
    if String.unsafe_get pat pos <>
      String.unsafe_get str epos then false else
      is_prefix (pos - 1) spos (epos - 1) in
  let rec search spos =
    let epos = spos + patlen - 1 in
    if epos >= strlen then raise Not_found else
    if is_prefix (patlen - 1) spos epos then spos else
    search (spos + 1) in
  search 0
    
(* checker's lame imperative strstr *)
let strstr_imp pat str = 
  let strlen = String.length str in
  let patlen = String.length pat and
      i = ref 0 and
      f = ref strlen in
  while !i < strlen do
    let pati = ref 0 and
        j = ref !i in
    while !pati < patlen && !j < strlen &&
      String.unsafe_get str !j == String.unsafe_get pat !pati do
        pati := succ !pati;
        j := succ !j;
    done;
    if !pati = patlen then
      begin f := !i; i := strlen end
    else
      i := succ !i
  done;
  !f

(* a really questionable timing harness *)
let time_strstr name strstr =
  let t0 = Unix.gettimeofday () in 
  for i = 0 to 100000 do
    strstr "this" "that this the other";
    strstr "this" "this that this the other";
    strstr "this" "that tis the other this";
    strstr "this" "that the othethisr th";
  done;
  let t = Unix.gettimeofday () -. t0 in
  Printf.printf "%s total = %f (%d,%d,%d,%d)\n" name t
  (* a really pathetic regression test *)
    (strstr "this" "that this the other")
    (strstr "this" "this that this the other")
    (strstr "this" "that tis the other this")
    (strstr "this" "that the othethisr th")

(* main *)
let _ = 
  time_strstr "strstr" strstr;
  time_strstr "strstr_imp" strstr_imp;
  time_strstr "strstr_c" Strstrc.strstr_c;



  parent reply	other threads:[~2000-12-12  9:20 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-12-08  6:04 eijiro_sumii
2000-12-08 12:57 ` Gerd Stolpmann
2000-12-10 13:16   ` eijiro_sumii
2000-12-10 15:39     ` Gerd Stolpmann
2000-12-11  3:57       ` eijiro_sumii
2000-12-12 13:58       ` Julian Assange
2000-12-11 21:07     ` Chris Hecker [this message]
2000-12-11 22:22       ` Gerd Stolpmann
2000-12-12  5:06         ` Chris Hecker
2000-12-12 12:28           ` Jean-Christophe Filliatre
2000-12-13 10:02             ` eijiro_sumii
2000-12-13 10:17               ` Eijiro Sumii
2000-12-13 10:53               ` Julian Assange
2000-12-13 13:28                 ` Eijiro Sumii
2000-12-12  3:28       ` eijiro_sumii
2000-12-13  1:12         ` John Prevost
2000-12-13  2:35           ` Chris Hecker
2000-12-12 10:07       ` Sven LUTHER
2000-12-14  3:36       ` eijiro_sumii
2000-12-14  6:48         ` Chris Hecker
2000-12-14  8:02           ` eijiro_sumii
2000-12-14 21:53             ` Stephan Tolksdorf
2000-12-14 21:12 Ruchira Datta

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4.3.2.7.2.20001211103237.00c12100@shell16.ba.best.com \
    --to=checker@d6.com \
    --cc=caml-list@inria.fr \
    --cc=eijiro_sumii@anet.ne.jp \
    --cc=gerd@gerd-stolpmann.de \
    --cc=sumii@venus.is.s.u-tokyo.ac.jp \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).