[m-rev.] diff: implement concat_string_list for .NET

Ralph Becket rafe at cs.mu.OZ.AU
Tue Feb 18 10:59:14 AEDT 2003


Michael Day, Monday, 17 February 2003:
> 
> > null-terminated strings. (In that case, you may have to scan a
> > string with an explicit length to search for nulls before the end of
> > the string, and even if that scan is negative, you may have to copy
> > the string to buffer that has room for the final null to be
> > inserted.)
> 
> Ouch, that's a nasty example of paying for stuff you don't use,
> considering that very few strings are going to be stuffed with nulls, and
> if they are then you won't have much luck passing them to C libraries or
> the operating system anyway.

There is a much more serious problem which is not related to the C/OS
interface.  Neither the Mercury compiler or GCC seems able to optimize
away redundant calls to string.length in a loop iterating over the chars
in a string.  This causes an O(n) algorithm to become O(n^2).

I've just written a small benchmark (see attached file a.m) which sums
the char codes over the length of a string, comparing the cost of
string.elem with string.unsafe_elem (clearly, using the former would be
preferable were it not so inefficient to do so.)

Using `mmc --make a -O5' I get the following times (obtained via
benchmark_func) on ceres (I got bored waiting for the `safe' results on
longer strings):

100 iterations over 2^13 char strings:
TSafe   =    17869 ms
TUnsafe =       10 ms

100 iterations over 2^12 char strings:
TSafe   =     4470 ms
TUnsafe =       10 ms

100 iterations over 2^11 char strings:
TSafe   =     1149 ms
TUnsafe =        0 ms

100 iterations over 2^10 char strings:
TSafe   =      305 ms
TUnsafe =        0 ms

100 iterations over 2^9 char strings:
TSafe   =       79 ms
TUnsafe =        0 ms

We can clearly see the O(n) --> O(n^2) effect.  The results are
unaffected if I turn on --transitive-intermodule-optimization.

So I'd argue there is either a problem with the optimizer or there is a
strong case for changing the representation of strings to support O(1)
calls to string.length.

	Ralph


p.s.  I get the following whinge from the compiler if I use -O6:

Making a.int3
Making a.opt
Making a.c
Making a.o
In file included from /home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/gc_inl.h:17,
                 from /home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/mercury.h:46,
                 from Mercury/mihs/a.mih:26,
                 from Mercury/cs/a.c:19:
/home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/private/gc_priv.h:57: warning: `TRUE' redefined
/home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/mercury_bootstrap.h:46: warning: this is the location of the previous definition
/home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/private/gc_priv.h:58: warning: `FALSE' redefined
/home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/mercury_bootstrap.h:49: warning: this is the location of the previous definition
In file included from /home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/private/gc_priv.h:70,
                 from /home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/gc_inl.h:17,
                 from /home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/mercury.h:47,
                 from Mercury/mihs/a.mih:26,
                 from Mercury/cs/a.c:19:
/home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/private/gcconfig.h:1978: warning: function declaration isn't a prototype
In file included from /home/ceres/public/mercury-latest/i686-pc-linux-gnu/lib/mercury/inc/gc_inl.h:17,
Making a

-------------- next part --------------
%-----------------------------------------------------------------------------%
% a.m
% Ralph Becket <rafe at cs.mu.oz.au>
% Tue Feb 18 10:03:54 EST 2003
% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
%
%-----------------------------------------------------------------------------%

:- module a.

:- interface.

:- import_module io.



:- pred main(io::di, io::uo) is cc_multi.

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%

:- implementation.

:- import_module std_util, string, char, int, list, benchmarking.

%-----------------------------------------------------------------------------%

main(!IO) :-

    S = pow(func(S0) = S0 ++ S0, 13, "x"),
    N = 100,

    io.format("Starting (safe) elem benchmark...\n", [], !IO),
    benchmark_func(loop(S, safe),   0, _, N, TSafe  ),

    io.format("Starting unsafe_elem benchmark...\n", [], !IO),
    benchmark_func(loop(S, unsafe), 0, _, N, TUnsafe),

    io.format("TSafe   = %8d ms\nTUnsafe = %8d ms\n",
        [i(TSafe), i(TUnsafe)], !IO).

%-----------------------------------------------------------------------------%

:- func loop(string, func(string, int, int, T) = T, T) = T.

loop(S, F, A) = F(S, 0, length(S), A).

%-----------------------------------------------------------------------------%

:- func safe(string, int, int, int) = int.

safe(S, I, N, A) =
    ( if I < N then safe(S, I + 1, N, A + to_int(S ^ elem(I)))
               else A ).

%-----------------------------------------------------------------------------%

:- func unsafe(string, int, int, int) = int.

unsafe(S, I, N, A) =
    ( if I < N then unsafe(S, I + 1, N, A + to_int(S ^ unsafe_elem(I)))
               else A ).

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%


More information about the reviews mailing list