From: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
To: Christoph Lameter <clameter@sgi.com>
Cc: Martin Bligh <mbligh@mbligh.org>,
Andi Kleen <andi@firstfloor.org>,
linux-kernel@vger.kernel.org, linux-mm@kvack.org,
David Miller <davem@davemloft.net>
Subject: Re: [patch 00/10] [RFC] SLUB patches for more functionality, performance and maintenance
Date: Tue, 10 Jul 2007 04:27:09 -0400 [thread overview]
Message-ID: <20070710082709.GC16148@Krystal> (raw)
In-Reply-To: <Pine.LNX.4.64.0707091715450.2062@schroedinger.engr.sgi.com>
* Christoph Lameter (clameter@sgi.com) wrote:
> Ok here is a replacement patch for the cmpxchg patch. Problems
>
> 1. cmpxchg_local is not available on all arches. If we wanted to do
> this then it needs to be universally available.
>
cmpxchg_local is not available on all archs, but local_cmpxchg is. It
expects a local_t type which is nothing else than a long. When the local
atomic operation is not more efficient or not implemented on a given
architecture, asm-generic/local.h falls back on atomic_long_t. If you
want, you could work on the local_t type, which you could cast from a
long to a pointer when you need so, since their size are, AFAIK, always
the same (and some VM code even assume this is always the case).
> 2. cmpxchg_local does generate the "lock" prefix. It should not do that.
> Without fixes to cmpxchg_local we cannot expect maximum performance.
>
Yup, see the patch I just posted for this.
> 3. The approach is x86 centric. It relies on a cmpxchg that does not
> synchronize with memory used by other cpus and therefore is more
> lightweight. As far as I know the IA64 cmpxchg cannot do that.
> Neither several other processors. I am not sure how cmpxchgless
> platforms would use that. We need a detailed comparison of
> interrupt enable /disable vs. cmpxchg cycle counts for cachelines in
> the cpu cache to evaluate the impact that such a change would have.
>
> The cmpxchg (or its emulation) does not need any barriers since the
> accesses can only come from a single processor.
>
Yes, expected improvements goes as follow:
x86, x86_64 : must faster due to non-LOCKed cmpxchg
alpha: should be faster due to memory barrier removal
mips: memory barriers removed
powerpc 32/64: memory barriers removed
On other architectures, either there is no better implementation than
the standard atomic cmpxchg or it just has not been implemented.
I guess that a test series that would tell us how must improvement is
seen on the optimized architectures (local cmpxchg vs interrupt
enable/disable) and also what effect the standard cmpxchg has compared
to interrupt disable/enable on the architectures where we can't do
better than the standard cmpxchg will tell us if it is an interesting
way to go. I would be happy to do these tests, but I don't have the
hardware handy. I provide a test module to get these characteristics
from various architectures in this email.
> Mathieu measured a significant performance benefit coming from not using
> interrupt enable / disable.
>
> Some rough processor cycle counts (anyone have better numbers?)
>
> STI CLI CMPXCHG
> IA32 36 26 1 (assume XCHG == CMPXCHG, sti/cli also need stack pushes/pulls)
> IA64 12 12 1 (but ar.ccv needs 11 cycles to set comparator,
> need register moves to preserve processors flags)
>
The measurements I get (in cycles):
enable interrupts (STI) disable interrupts (CLI) local CMPXCHG
IA32 (P4) 112 82 26
x86_64 AMD64 125 102 19
> Looks like STI/CLI is pretty expensive and it seems that we may be able to
> optimize the alloc / free hotpath quite a bit if we could drop the
> interrupt enable / disable. But we need some measurements.
>
>
> Draft of a new patch:
>
> SLUB: Single atomic instruction alloc/free using cmpxchg_local
>
> A cmpxchg allows us to avoid disabling and enabling interrupts. The cmpxchg
> is optimal to allow operations on per cpu freelist. We can stay on one
> processor by disabling preemption() and allowing concurrent interrupts
> thus avoiding the overhead of disabling and enabling interrupts.
>
> Pro:
> - No need to disable interrupts.
> - Preempt disable /enable vanishes on non preempt kernels
> Con:
> - Slightly complexer handling.
> - Updates to atomic instructions needed
>
> Signed-off-by: Christoph Lameter <clameter@sgi.com>
>
Test local cmpxchg vs int disable/enable. Please run on a 2.6.22 kernel
(or recent 2.6.21-rcX-mmX) (with my cmpxchg local fix patch for x86_64).
Make sure the TSC reads (get_cycles()) are reliable on your platform.
Mathieu
/* test-cmpxchg-nolock.c
*
* Compare local cmpxchg with irq disable / enable.
*/
#include <linux/jiffies.h>
#include <linux/compiler.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/calc64.h>
#include <asm/timex.h>
#include <asm/system.h>
#define NR_LOOPS 20000
int test_val = 0;
static void do_test_cmpxchg(void)
{
int ret;
long flags;
unsigned int i;
cycles_t time1, time2, time;
long rem;
local_irq_save(flags);
preempt_disable();
time1 = get_cycles();
for (i = 0; i < NR_LOOPS; i++) {
ret = cmpxchg_local(&test_val, 0, 0);
}
time2 = get_cycles();
local_irq_restore(flags);
preempt_enable();
time = time2 - time1;
printk(KERN_ALERT "test results: time for non locked cmpxchg\n");
printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
printk(KERN_ALERT "total time: %llu\n", time);
time = div_long_long_rem(time, NR_LOOPS, &rem);
printk(KERN_ALERT "-> non locked cmpxchg takes %llu cycles\n", time);
printk(KERN_ALERT "test end\n");
}
/*
* This test will have a higher standard deviation due to incoming interrupts.
*/
static void do_test_enable_int(void)
{
long flags;
unsigned int i;
cycles_t time1, time2, time;
long rem;
local_irq_save(flags);
preempt_disable();
time1 = get_cycles();
for (i = 0; i < NR_LOOPS; i++) {
local_irq_restore(flags);
}
time2 = get_cycles();
local_irq_restore(flags);
preempt_enable();
time = time2 - time1;
printk(KERN_ALERT "test results: time for enabling interrupts (STI)\n");
printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
printk(KERN_ALERT "total time: %llu\n", time);
time = div_long_long_rem(time, NR_LOOPS, &rem);
printk(KERN_ALERT "-> enabling interrupts (STI) takes %llu cycles\n",
time);
printk(KERN_ALERT "test end\n");
}
static void do_test_disable_int(void)
{
unsigned long flags, flags2;
unsigned int i;
cycles_t time1, time2, time;
long rem;
local_irq_save(flags);
preempt_disable();
time1 = get_cycles();
for ( i = 0; i < NR_LOOPS; i++) {
local_irq_save(flags2);
}
time2 = get_cycles();
local_irq_restore(flags);
preempt_enable();
time = time2 - time1;
printk(KERN_ALERT "test results: time for disabling interrupts (CLI)\n");
printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
printk(KERN_ALERT "total time: %llu\n", time);
time = div_long_long_rem(time, NR_LOOPS, &rem);
printk(KERN_ALERT "-> disabling interrupts (CLI) takes %llu cycles\n",
time);
printk(KERN_ALERT "test end\n");
}
static int ltt_test_init(void)
{
printk(KERN_ALERT "test init\n");
do_test_cmpxchg();
do_test_enable_int();
do_test_disable_int();
return -EAGAIN; /* Fail will directly unload the module */
}
static void ltt_test_exit(void)
{
printk(KERN_ALERT "test exit\n");
}
module_init(ltt_test_init)
module_exit(ltt_test_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mathieu Desnoyers");
MODULE_DESCRIPTION("Cmpxchg local test");
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
WARNING: multiple messages have this Message-ID (diff)
From: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
To: Christoph Lameter <clameter@sgi.com>
Cc: Martin Bligh <mbligh@mbligh.org>,
Andi Kleen <andi@firstfloor.org>,
linux-kernel@vger.kernel.org, linux-mm@kvack.org,
David Miller <davem@davemloft.net>
Subject: Re: [patch 00/10] [RFC] SLUB patches for more functionality, performance and maintenance
Date: Tue, 10 Jul 2007 04:27:09 -0400 [thread overview]
Message-ID: <20070710082709.GC16148@Krystal> (raw)
In-Reply-To: <Pine.LNX.4.64.0707091715450.2062@schroedinger.engr.sgi.com>
* Christoph Lameter (clameter@sgi.com) wrote:
> Ok here is a replacement patch for the cmpxchg patch. Problems
>
> 1. cmpxchg_local is not available on all arches. If we wanted to do
> this then it needs to be universally available.
>
cmpxchg_local is not available on all archs, but local_cmpxchg is. It
expects a local_t type which is nothing else than a long. When the local
atomic operation is not more efficient or not implemented on a given
architecture, asm-generic/local.h falls back on atomic_long_t. If you
want, you could work on the local_t type, which you could cast from a
long to a pointer when you need so, since their size are, AFAIK, always
the same (and some VM code even assume this is always the case).
> 2. cmpxchg_local does generate the "lock" prefix. It should not do that.
> Without fixes to cmpxchg_local we cannot expect maximum performance.
>
Yup, see the patch I just posted for this.
> 3. The approach is x86 centric. It relies on a cmpxchg that does not
> synchronize with memory used by other cpus and therefore is more
> lightweight. As far as I know the IA64 cmpxchg cannot do that.
> Neither several other processors. I am not sure how cmpxchgless
> platforms would use that. We need a detailed comparison of
> interrupt enable /disable vs. cmpxchg cycle counts for cachelines in
> the cpu cache to evaluate the impact that such a change would have.
>
> The cmpxchg (or its emulation) does not need any barriers since the
> accesses can only come from a single processor.
>
Yes, expected improvements goes as follow:
x86, x86_64 : must faster due to non-LOCKed cmpxchg
alpha: should be faster due to memory barrier removal
mips: memory barriers removed
powerpc 32/64: memory barriers removed
On other architectures, either there is no better implementation than
the standard atomic cmpxchg or it just has not been implemented.
I guess that a test series that would tell us how must improvement is
seen on the optimized architectures (local cmpxchg vs interrupt
enable/disable) and also what effect the standard cmpxchg has compared
to interrupt disable/enable on the architectures where we can't do
better than the standard cmpxchg will tell us if it is an interesting
way to go. I would be happy to do these tests, but I don't have the
hardware handy. I provide a test module to get these characteristics
from various architectures in this email.
> Mathieu measured a significant performance benefit coming from not using
> interrupt enable / disable.
>
> Some rough processor cycle counts (anyone have better numbers?)
>
> STI CLI CMPXCHG
> IA32 36 26 1 (assume XCHG == CMPXCHG, sti/cli also need stack pushes/pulls)
> IA64 12 12 1 (but ar.ccv needs 11 cycles to set comparator,
> need register moves to preserve processors flags)
>
The measurements I get (in cycles):
enable interrupts (STI) disable interrupts (CLI) local CMPXCHG
IA32 (P4) 112 82 26
x86_64 AMD64 125 102 19
> Looks like STI/CLI is pretty expensive and it seems that we may be able to
> optimize the alloc / free hotpath quite a bit if we could drop the
> interrupt enable / disable. But we need some measurements.
>
>
> Draft of a new patch:
>
> SLUB: Single atomic instruction alloc/free using cmpxchg_local
>
> A cmpxchg allows us to avoid disabling and enabling interrupts. The cmpxchg
> is optimal to allow operations on per cpu freelist. We can stay on one
> processor by disabling preemption() and allowing concurrent interrupts
> thus avoiding the overhead of disabling and enabling interrupts.
>
> Pro:
> - No need to disable interrupts.
> - Preempt disable /enable vanishes on non preempt kernels
> Con:
> - Slightly complexer handling.
> - Updates to atomic instructions needed
>
> Signed-off-by: Christoph Lameter <clameter@sgi.com>
>
Test local cmpxchg vs int disable/enable. Please run on a 2.6.22 kernel
(or recent 2.6.21-rcX-mmX) (with my cmpxchg local fix patch for x86_64).
Make sure the TSC reads (get_cycles()) are reliable on your platform.
Mathieu
/* test-cmpxchg-nolock.c
*
* Compare local cmpxchg with irq disable / enable.
*/
#include <linux/jiffies.h>
#include <linux/compiler.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/calc64.h>
#include <asm/timex.h>
#include <asm/system.h>
#define NR_LOOPS 20000
int test_val = 0;
static void do_test_cmpxchg(void)
{
int ret;
long flags;
unsigned int i;
cycles_t time1, time2, time;
long rem;
local_irq_save(flags);
preempt_disable();
time1 = get_cycles();
for (i = 0; i < NR_LOOPS; i++) {
ret = cmpxchg_local(&test_val, 0, 0);
}
time2 = get_cycles();
local_irq_restore(flags);
preempt_enable();
time = time2 - time1;
printk(KERN_ALERT "test results: time for non locked cmpxchg\n");
printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
printk(KERN_ALERT "total time: %llu\n", time);
time = div_long_long_rem(time, NR_LOOPS, &rem);
printk(KERN_ALERT "-> non locked cmpxchg takes %llu cycles\n", time);
printk(KERN_ALERT "test end\n");
}
/*
* This test will have a higher standard deviation due to incoming interrupts.
*/
static void do_test_enable_int(void)
{
long flags;
unsigned int i;
cycles_t time1, time2, time;
long rem;
local_irq_save(flags);
preempt_disable();
time1 = get_cycles();
for (i = 0; i < NR_LOOPS; i++) {
local_irq_restore(flags);
}
time2 = get_cycles();
local_irq_restore(flags);
preempt_enable();
time = time2 - time1;
printk(KERN_ALERT "test results: time for enabling interrupts (STI)\n");
printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
printk(KERN_ALERT "total time: %llu\n", time);
time = div_long_long_rem(time, NR_LOOPS, &rem);
printk(KERN_ALERT "-> enabling interrupts (STI) takes %llu cycles\n",
time);
printk(KERN_ALERT "test end\n");
}
static void do_test_disable_int(void)
{
unsigned long flags, flags2;
unsigned int i;
cycles_t time1, time2, time;
long rem;
local_irq_save(flags);
preempt_disable();
time1 = get_cycles();
for ( i = 0; i < NR_LOOPS; i++) {
local_irq_save(flags2);
}
time2 = get_cycles();
local_irq_restore(flags);
preempt_enable();
time = time2 - time1;
printk(KERN_ALERT "test results: time for disabling interrupts (CLI)\n");
printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
printk(KERN_ALERT "total time: %llu\n", time);
time = div_long_long_rem(time, NR_LOOPS, &rem);
printk(KERN_ALERT "-> disabling interrupts (CLI) takes %llu cycles\n",
time);
printk(KERN_ALERT "test end\n");
}
static int ltt_test_init(void)
{
printk(KERN_ALERT "test init\n");
do_test_cmpxchg();
do_test_enable_int();
do_test_disable_int();
return -EAGAIN; /* Fail will directly unload the module */
}
static void ltt_test_exit(void)
{
printk(KERN_ALERT "test exit\n");
}
module_init(ltt_test_init)
module_exit(ltt_test_exit)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mathieu Desnoyers");
MODULE_DESCRIPTION("Cmpxchg local test");
--
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F BA06 3F25 A8FE 3BAE 9A68
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2007-07-10 8:27 UTC|newest]
Thread overview: 111+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-08 3:49 [patch 00/10] [RFC] SLUB patches for more functionality, performance and maintenance Christoph Lameter
2007-07-08 3:49 ` [patch 01/10] SLUB: Direct pass through of page size or higher kmalloc requests Christoph Lameter
2007-07-08 3:49 ` [patch 02/10] SLUB: Avoid page struct cacheline bouncing due to remote frees to cpu slab Christoph Lameter
2007-07-08 3:49 ` [patch 03/10] SLUB: Do not use page->mapping Christoph Lameter
2007-07-08 3:49 ` [patch 04/10] SLUB: Move page->offset to kmem_cache_cpu->offset Christoph Lameter
2007-07-08 3:49 ` [patch 05/10] SLUB: Avoid touching page struct when freeing to per cpu slab Christoph Lameter
2007-07-08 3:49 ` [patch 06/10] SLUB: Place kmem_cache_cpu structures in a NUMA aware way Christoph Lameter
2007-07-08 3:49 ` [patch 07/10] SLUB: Optimize cacheline use for zeroing Christoph Lameter
2007-07-08 3:50 ` [patch 08/10] SLUB: Single atomic instruction alloc/free using cmpxchg Christoph Lameter
2007-07-08 3:50 ` [patch 09/10] Remove the SLOB allocator for 2.6.23 Christoph Lameter
2007-07-08 7:51 ` Ingo Molnar
2007-07-08 9:43 ` Nick Piggin
2007-07-08 9:54 ` Ingo Molnar
2007-07-08 10:23 ` Nick Piggin
2007-07-08 10:42 ` Ingo Molnar
2007-07-08 18:02 ` Andrew Morton
2007-07-09 2:57 ` Nick Piggin
2007-07-09 11:04 ` Pekka Enberg
2007-07-09 11:16 ` Nick Piggin
2007-07-09 12:47 ` Pekka Enberg
2007-07-09 13:46 ` Pekka J Enberg
2007-07-09 16:08 ` Christoph Lameter
2007-07-09 16:08 ` Christoph Lameter
2007-07-10 8:17 ` Pekka J Enberg
2007-07-10 8:17 ` Pekka J Enberg
2007-07-10 8:27 ` Nick Piggin
2007-07-10 8:27 ` Nick Piggin
2007-07-10 9:31 ` Pekka Enberg
2007-07-10 9:31 ` Pekka Enberg
2007-07-10 10:09 ` Nick Piggin
2007-07-10 10:09 ` Nick Piggin
2007-07-10 12:02 ` Matt Mackall
2007-07-10 12:02 ` Matt Mackall
2007-07-10 12:57 ` Pekka J Enberg
2007-07-10 12:57 ` Pekka J Enberg
2007-07-10 22:12 ` Christoph Lameter
2007-07-10 22:40 ` Matt Mackall
2007-07-10 22:40 ` Matt Mackall
2007-07-10 22:50 ` Christoph Lameter
2007-07-10 22:50 ` Christoph Lameter
2007-07-09 16:06 ` Christoph Lameter
2007-07-09 16:51 ` Andrew Morton
2007-07-09 17:26 ` Christoph Lameter
2007-07-09 18:00 ` Andrew Morton
2007-07-10 1:43 ` Nick Piggin
2007-07-10 1:56 ` Christoph Lameter
2007-07-10 2:02 ` Nick Piggin
2007-07-10 2:11 ` Christoph Lameter
2007-07-10 7:09 ` Nick Piggin
2007-07-10 22:09 ` Christoph Lameter
2007-07-10 23:12 ` Matt Mackall
2007-07-10 8:32 ` Matt Mackall
2007-07-10 9:01 ` Håvard Skinnemoen
2007-07-10 9:11 ` Nick Piggin
2007-07-10 9:21 ` Håvard Skinnemoen
2007-07-11 1:37 ` Christoph Lameter
2007-07-11 2:06 ` Matt Mackall
2007-07-11 18:06 ` Christoph Lameter
2007-07-11 18:25 ` Pekka J Enberg
2007-07-11 18:33 ` Christoph Lameter
2007-07-11 18:36 ` Pekka J Enberg
2007-07-12 0:33 ` Nick Piggin
2007-07-09 23:09 ` Matt Mackall
2007-07-10 1:41 ` Nick Piggin
2007-07-10 1:51 ` Christoph Lameter
2007-07-10 1:58 ` Nick Piggin
2007-07-10 6:22 ` Matt Mackall
2007-07-10 7:03 ` Nick Piggin
2007-07-10 2:32 ` Matt Mackall
2007-07-09 21:57 ` Matt Mackall
2007-07-09 12:31 ` Matthieu CASTET
2007-07-09 16:00 ` Christoph Lameter
2007-07-09 20:52 ` Matt Mackall
2007-07-08 3:50 ` [patch 10/10] Remove slab in 2.6.24 Christoph Lameter
2007-07-08 4:37 ` [patch 00/10] [RFC] SLUB patches for more functionality, performance and maintenance David Miller
2007-07-09 15:45 ` Christoph Lameter
2007-07-09 19:43 ` David Miller
2007-07-09 21:21 ` Christoph Lameter
2007-07-08 11:20 ` Andi Kleen
2007-07-09 15:50 ` Christoph Lameter
2007-07-09 15:50 ` Christoph Lameter
2007-07-09 15:59 ` Martin Bligh
2007-07-09 15:59 ` Martin Bligh
2007-07-09 18:11 ` Christoph Lameter
2007-07-09 18:11 ` Christoph Lameter
2007-07-09 21:00 ` Martin Bligh
2007-07-09 21:00 ` Martin Bligh
2007-07-09 21:44 ` Mathieu Desnoyers
2007-07-09 21:44 ` Mathieu Desnoyers
2007-07-09 21:55 ` Christoph Lameter
2007-07-09 21:55 ` Christoph Lameter
2007-07-09 22:58 ` Mathieu Desnoyers
2007-07-09 22:58 ` Mathieu Desnoyers
2007-07-09 23:08 ` Christoph Lameter
2007-07-09 23:08 ` Christoph Lameter
2007-07-10 5:16 ` [PATCH] x86_64 - Use non locked version for local_cmpxchg() Mathieu Desnoyers
2007-07-10 5:16 ` Mathieu Desnoyers
2007-07-10 20:46 ` Christoph Lameter
2007-07-10 20:46 ` Christoph Lameter
2007-07-10 0:55 ` [patch 00/10] [RFC] SLUB patches for more functionality, performance and maintenance Christoph Lameter
2007-07-10 0:55 ` Christoph Lameter
2007-07-10 8:27 ` Mathieu Desnoyers [this message]
2007-07-10 8:27 ` Mathieu Desnoyers
2007-07-10 18:38 ` Christoph Lameter
2007-07-10 18:38 ` Christoph Lameter
2007-07-10 20:59 ` Mathieu Desnoyers
2007-07-10 20:59 ` Mathieu Desnoyers
2007-08-13 22:18 ` Mathieu Desnoyers
2007-08-13 22:18 ` Mathieu Desnoyers
2007-08-13 22:28 ` Christoph Lameter
2007-08-13 22:28 ` Christoph Lameter
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=20070710082709.GC16148@Krystal \
--to=mathieu.desnoyers@polymtl.ca \
--cc=andi@firstfloor.org \
--cc=clameter@sgi.com \
--cc=davem@davemloft.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mbligh@mbligh.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.