Interchange Guides: Optimization

DavorOcelic

MikeHeins

This documentation is free; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

Software optimizations

Interchange

General-purpose benchmarking

One of the most simple and straightforward methods to check whether
the code is able to complete a task within a reasonable time is
benchmarking. For the purpose, Interchange offers
the benchmark tag which is found in the
eg/usertag/ directory of
the Interchange tarball distribution.

The benchmark reference page contains all the relevant
installation and usage notes.

Optimizing lists

Interchange has powerful capabilities (such as searching) that allow
you to produce lists of items for use in category lists, product lists,
indexes, and other navigation tools or data reports.

These are a two-edged sword, though. Lists of hundreds or thousands of
entries can be returned, and techniques that work well displaying only
a few items may slow to a crawl when a large list is returned.

In general, when you are displaying only one item (such as on a
flypage) or a small list (such as shopping cart contents),
you can be pretty carefree in your use of ITL tags.
When there are thousands of items, though, you cannot; each
ITL tag requires parsing and argument building, and all
complex tests or embedded Perl blocks cause the
Safe module to evaluate code.

The Safe module is pretty fast considering
what it does, but it can only generate a few thousand instances per
second even on a fast system. And the ITL tag
parser can likewise only parse thousands of tags per CPU second.

What to do? You want to provide complex conditional tests but you
don't want your system to slow to a crawl. Luckily, there are
techniques which can speed up complex lists by orders of magnitude.

[PREFIX-tag]

[PREFIX-tag] constructs
are the fastest way to retrieve loop data. Let's say we want to
find all our products (search in all ProductFiles databases)
and display descriptions of all the products found:

The loop tags are interpreted by means of fast regular expression
scans of the loop container text, and fetch an entire row of
data in one query.

The data ITL tag interpretation is
delayed until after the loop is finished, whereby the ITL tag
parser must find the tag, build a parameter list, and then fetch the
data with a separate query.

If there are repeated references to the same field in the loop,
the speedup can be 10x or more.

Pre-fetch data

The mv_return_fields variable (otherwise known as the
"rf" parameter in one-click terminology) defines
a comma-separated list of fields you want returned from a search.
This, in effect, kind of pre-fetches the data you want to use within
a loop.

Once the records are returned, the fields can be accessed using the
[PREFIX-param field] syntax.
The fields can also be referenced using [PREFIX-pos N],
where the N represents the ordinal position
(starting from 0) in the field list.

That said, the following are equivalent in effect but the
second variant is much, much faster:

The above is a hundred times faster than anything you can build with
multiple calc tags.

Use [PREFIX-calc] instead of [calc] or [perl]

Using [PREFIX-calc], you
can execute the same code as with calc, but with two benefits:
you will not trigger ITL parsing, and the code will be
executed during the loop instead of
after it.

The [PREFIX-calc] object
has complete access to all normal embedded Perl objects like
$Values, $Carts,
$Tag, and such. If you want to access data tables
from within the loop (such as products or
pricing), just call the following
above the loop:

[perl tables="products pricing" /]

ADVANCED: Precompile and execute

For repetitive routines, you can achieve a considerable savings
in CPU by pre-compiling your embedded Perl code. The precompilation
can occur either once at catalog configuration time,
or once at time of list execution.

When you compile routines at the time of the list execution
(using [item-sub NAME] ... CODE ... [/item-sub]), only one
Safe evaluation will be done, and every
time the [loop-exec NAME]
is called, it will be a direct call to the routine. This can be
10 times or more faster than separate calc calls, or 5 times
faster than separate
[PREFIX-calc calls. Here's
an example:

Interpolation and reparsing

Avoid interpolate=1 and
reparse=1 whenever possible. A separate tag parser
must be spawned every time you do this. Many times people use this
without needing it.

Session variables

Avoid saving large values to scratch space, as these will be
written to the users session. If you need them only for the current
page, use tmpn and tmp instead of set and seti
(temporary variables are automatically deleted at the end of current
page processing - before the user's session is saved).

You can also retrieve values using [scratchd VARIABLE_NAME]
to return the contents and delete them from the session at the same
time.