lyx_mirror/development/lazy_lyxtext.txt

120 lines
5.0 KiB
Plaintext
Raw Permalink Normal View History

Lazy Generation of LyXText
--------------------------
Currently we generate the Row structure at the time of LyXText
creation. This is the "formatting" period of the document
loading. As can be seen this has a significant hit on the amount
of time used to load large documents. On my computer this
manifests itself as a 15 second load time of the UserGuide. In
many ways this is acceptable, but we actually get the same hit
when switching between documents. Because of this the TextCache
was created, however it seems that textcache has some internal
problems or it makes problems in LyXText show.
My suggestion is to make LyXText only generate Rows as need, i.e.
lazy evaluation/generation of the on screen formatting. This will
give us: blinding fast document loading. It also lessens the need
for the TextCache class significantly and with some small further
alterations TextCache can be removed completely.
The Rows are currently stored in a home made double linked list.
To achieve the lazy evaluation this should be changed slightly:
struct RowPar {
// Pointer to the paragraph that this rowpar holds rows for.
LyXParagraph * par;
// Only used for lazy evaluation when switching between buffers.
unsigned int par_y;
typedef vector<Row> Rows;
// The actual rows, generated as needed.
Rows rows;
};
struct Row {
LyXParagraph::size_type pos;
mutable int fill;
unsigned short height;
unsigned short ascent_of_text;
unsigned baseline;
};
typedef list<RowPar> ParRowList;
ParRowList parrow;
Several LyXText methods needs to be changed to handle this new
structure.
Note about RowPar::par_y: If we only want top-down<77> this variable
is not needed. If we however want to be able to begin evaluation
at the location of the cursor it is needed. Then we don't have to
store the formatted document in the textcache. Only a list of
struct Cache {
LyXParagraph * par;
unsigned int par_y;
};
is needed. Since we regenerate all the rows subtleties with row
lifetime etc. are avoided.
Memory usage: the current Row has a size of about 28 bytes on a
32 bit machine and we have one Row for each line on the screen.
For a 10 page document with ca. 50 lines on each page this is
28 * 10 * 50 = 14000 bytes.
The approach above has three pointer less in each row, so
this is 16 * 10 * 50 = 8000 bytes, we have however some
additional overhead: the RowPars one for each paragraph if we
assume 5 lines per paragraph and 20 bytes for each RowPar we get:
10 * 50 / 5 * 20 = 2000. This is a sum of 10000 on the new scheme.
Speed: some operations will most likely be somewhat faster since
they now can operate on the number of paragraph instead of the
number of rows. I do not foresee any operations becoming slower.
The actual lazy evaluation will be done upon displaying, and when
the lyx process is idle (idle_callback), this will mostly be
initiated by LyXScreen and done in LyXText::GetRowNearY and in
LyXText::GetRow. Perhaps also in LyXText::GetVisibleRow. All of
the evaluation will be done on a per-paragraph basis.
If we want to operate on rows only it is easy to create iterators
that can handle this. (This means that a way to force the
evaluation of the rows might be something like:
// traverse all the rows and generate the missing ones.
for_each(rowlist.begin(), rowlist.end(), dummy_func);
Note about the buffer structure in the lyx repository: LyXText
really is orthogonal to the new buffer structure in that the
BufferStructure is used for storage of the paragraphs, and
LyXText is used for the caching of on-screen display (of
lines/rows).
Note on impact on other code: Since the current rowlist is
internal to LyXText the impact on code outside LyXText will be
very small. However _inside_ LyXText the impact will be huge, and
all methods that access the rowlist will have to change.
When to begin coding on this. Of course since this is something
that I want to do, I'd like to begin right away. There can be
argued that this should wait until table and floats has been
moved out of LyXText, but I only partially agree. These changes
will be on a fairly low-level and the removal of table and floats
will not impact the development of this code much. Also this can
very well be done in a separate branch in cvs. Anyway this coding
will not begin until after 1.1.5 is released.
Fun stuff: Instead of doing the lazy evaluation only when needed
or by the idle callback this could also be done by a separate
thread taking advantage of SMP and/or io-blocking in the main
thread. We could even have the evaluation of each paragraph we
done in its own thread (or by a few<65> worker threads)
Lgb
<EFBFBD> Row evaluation from the beginning of the document to the end. Never
from the middle.
<EFBFBD> Number of CPUs f.ex.