Re: Bug 688602 requires a fundamental change to the memory management.
"Leonardo" <[email protected]> Fri, 14 Apr 2006 11:37:25 +0400
| Newsgroups | gmane.comp.printing.ghostscript.patches |
|---|---|
| Message-ID | <[email protected]> |
This is a multi-part message in MIME format.
------=_NextPart_000_0008_01C65FB7.CD1001B0
Content-Type: text/plain; format=flowed; charset="koi8-r"; reply-type=original
Content-Transfer-Encoding: 7bit
This is a release candidate.
It is being tested now.
Leo.
------=_NextPart_000_0008_01C65FB7.CD1001B0
Content-Type: application/octet-stream;
name="patch.txt "
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="patch.txt "
[Log message end]
Reduce the CPU time expense for 'restore'.
DETAILS :
This is a preparation for fixing=20
Bug 688602 "Displaying file with GS-8.53 is much slower than with =
GS-8.51".
Currently the new code is disabled with the macro NO_INVISIBLE_LEVELS
defined in gxalloc.h .=20
The performance flaw happened in revision 5980.
Before it the memery manager created "invisible" save levels
when the changes list becomes too long and needs a big time for=20
restoring l_new marks. The idea was to skip marls for=20
older changes so that they don't consume processor time.
The cost was an extra growth of the changes list,
because such changes are stored at second time
if happen again after the "invisible" 'save'.
While fixing the bug 68815 this optimization was lost
because it was not documented.
In same time, "invisible" 'save' levels appear logically incorrect,
because they cause the problem documented in the bug 68815.
This change implements same idea (the skipping of old changes
while 'restore'), but it does that with no extra 'save' levels.
The new implementation maintains a pointer=20
gs_ref_memory_t::scan_limit, which points=20
to a middle element of the changes list.
Elements after that pointers do not restore
l_new mark during 'restore'. Besides that,
this change introduces a new kind of change list elements,
which is marked with AC_OFFSET_ALLOCATED in the 'offset' field.
Such elements do not represent a memory content change,=20
but they represent an allocation event for 'ref' arrays.
The l_new mark is restored for those refs,
which were allocated after the change element
pointed by gs_ref_memory_t::scan_limit.
To simplify debugging, we define a new switch
NO_INVISIBLE_LEVELS in gxalloc.h .
When NO_INVISIBLE_LEVELS is zero,=20
an algorithmically equivalent change happens in isave.c
and igcref.c, and other modules are not affected.
In this case :
1. Factored out a new function mark_allocated (isave.c).
2. Added a new argument to save_set_new, save_set_new_changes
to know that it is called for an invisible level (isave.c).
3. Factored out a new function igc_reloc_ref_ptr_nocheck (igcref.c).
When NO_INVISIBLE_LEVELS is 1 :
1. Invisible save levels are not created=20
(the change to alloc_save_state in isave.c).
2. Instead that, it creates a new kind of alloc_change_t element,=20
which is marked with AC_OFFSET_ALLOCATED in the 'offset' field.
Such element points to the beginning of a newly allocated 'ref' array
(either packed or not) (see alloc_save_change_alloc in isave.c).
3. The new function alloc_save_remove removes such elements when
the object is being removed explicitely.
4. save_set_new is expanded to process the new kind of alloc_change_t =
elements.
With such elements it calls mark_allocated (see above),
so that the effect is same as before the patch.
5. The scanning of allocated objects in save_set_new is removed
due to (3).
6. save_set_new_changes is extended with computing the size of=20
newly allocated 'ref' arrays, which are processed during the scan.
It appears to be close to what save_set_new did while scanning
allocated objects (the variable 'changed').
7. The new field gs_ref_memory_t::scan_limit stores a termination
condition for scanning objects in save_set_new_changes.
The value is stored when save_set_new_changes is called=20
from alloc_save_state as it was for creatng an invisible save level.
Rather the new code doesn't create an invisible level,=20
the scan termination condition work as it were created.
8. save_set_new_changes uses the variable 'changed'
for a proper setting of the termination condition.
The condition is not exactly equivalent to the
old one, because the old code also accounts=20
a scanning of non-ref objects, but the new code
doesn't bother with them. Therefore new termination conditions
appear in some different points than invisible levels did.
Therefore the behavior isn't algorithmically equivalent.
9. The new code always restore to a 'visible' level.
In same time, doing a 'restore', some of l_new marks
may be left unrestored due to the scan tremination condition.
This effect may be considered as caching a reasonable
number of recently changed objects by marking with l_new.
Older changes loose the l_new mark and their further changes
will be stored again in the 'changes' list.=20
This causes an extra growth of the 'changes' list,
but saves the processor time from redundant setting
of multiple l_new marks when save-restore is executed
multiple times after a big number of changes.
10. The garbager implements a special processing for=20
AC_OFFSET_ALLOCATED elements. The 'where' pointer is not
enumerated and isn't tracked while the marking phase.
Instead that the garbager calls a special function=20
alloc_save__filter_changes to remove those elements,=20
which point to unused ref blocks. Also a special function
igc_reloc_ref_ptr_nocheck is used to relocate
'where' pointers. See comments in code.
11. In AC_OFFSET_ALLOCATED elements 60% of their size
appears unused. We would like to define a smaller
structure for them, but we don't want=20
enlarge the CPU time expense for checking types
in loops.
Thus NO_INVISIBLE_LEVELS 1 reconstructs the optimization,=20
which was lost while fixing the bug 688153 with the revision 5980.
Rather the behavior isn't strongly equivalent,
the overall logic is mostly same.
Now we commit this patch with new code disabled.
We'll enable it separately after the regression testing
of the algorithmically equivalent part.
EXPECTED DIFFERENCES :
None.
[Log message end]
=20
=20
=20
=20
*** F:\SVN-GS\HEAD\gs\src\gsalloc.c Wed Mar 15 15:04:22 2006
--- files\gs\src\gsalloc.c Wed Apr 12 14:50:54 2006
***************
*** 86,89 ****
--- 86,92 ----
ENUM_PTR3(0, gs_ref_memory_t, streams, names_array, changes);
ENUM_PTR(3, gs_ref_memory_t, saved);
+ #if NO_INVISIBLE_LEVELS
+ ENUM_PTR(4, gs_ref_memory_t, scan_limit);
+ #endif
ENUM_PTRS_END
private RELOC_PTRS_WITH(ref_memory_reloc_ptrs, gs_ref_memory_t *mptr)
***************
*** 92,95 ****
--- 95,101 ----
RELOC_PTR(gs_ref_memory_t, names_array);
RELOC_PTR(gs_ref_memory_t, changes);
+ #if NO_INVISIBLE_LEVELS
+ RELOC_PTR(gs_ref_memory_t, scan_limit);
+ #endif
/* Don't relocate the saved pointer now -- see igc.c for details. =
*/
mptr->reloc_saved =3D RELOC_OBJ(mptr->saved);
***************
*** 323,326 ****
--- 329,336 ----
mem->inherited =3D 0;
mem->changes =3D 0;
+ #if NO_INVISIBLE_LEVELS
+ mem->scan_limit =3D 0;
+ mem->total_scanned =3D 0;
+ #endif
ialloc_reset_free(mem);
}
=20
=20
=20
*** F:\SVN-GS\HEAD\gs\src\gxalloc.h Wed Mar 15 15:04:25 2006
--- files\gs\src\gxalloc.h Thu Apr 6 17:17:04 2006
***************
*** 27,30 ****
--- 27,32 ----
#include "gxobj.h"
=20
+ #define NO_INVISIBLE_LEVELS 1 /* old code =3D 0, new code =3D 1 */
+=20
/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Chunks =
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D */
=20
***************
*** 381,384 ****
--- 383,389 ----
int num_contexts; /* # of contexts sharing this VM */
struct alloc_change_s *changes;
+ #if NO_INVISIBLE_LEVELS
+ struct alloc_change_s *scan_limit;
+ #endif
struct alloc_save_s *saved;
long total_scanned;
***************
*** 397,401 ****
gs_public_st_composite(st_ref_memory, gs_ref_memory_t,\
"gs_ref_memory", ref_memory_enum_ptrs, ref_memory_reloc_ptrs)
! #define st_ref_memory_max_ptrs 4 /* streams, names_array, changes, =
saved */
=20
/* Define the procedures for the standard allocator. */
--- 402,406 ----
gs_public_st_composite(st_ref_memory, gs_ref_memory_t,\
"gs_ref_memory", ref_memory_enum_ptrs, ref_memory_reloc_ptrs)
! #define st_ref_memory_max_ptrs 5 /* streams, names_array, changes, =
scan_limit, saved */
=20
/* Define the procedures for the standard allocator. */
=20
=20
=20
*** F:\SVN-GS\HEAD\gs\src\ialloc.c Wed Mar 15 15:04:20 2006
--- files\gs\src\ialloc.c Wed Apr 12 11:24:20 2006
***************
*** 186,190 ****
chunk_t *pcc =3D mem->pcc;
ref *end;
!=20
obj =3D gs_alloc_struct_array((gs_memory_t *) mem, num_refs + 1,
ref, &st_refs, cname);
--- 186,199 ----
chunk_t *pcc =3D mem->pcc;
ref *end;
! #if NO_INVISIBLE_LEVELS
! ref_packed **ppr =3D 0;
! int code =3D 0;
!=20
! if ((gs_memory_t *)mem !=3D mem->stable_memory) {
! code =3D alloc_save_change_alloc(mem, "gs_alloc_ref_array", =
&ppr);
! if (code < 0)
! return code;
! }
! #endif
obj =3D gs_alloc_struct_array((gs_memory_t *) mem, num_refs + 1,
ref, &st_refs, cname);
***************
*** 211,214 ****
--- 220,227 ----
cl.cp->has_refs =3D true;
}
+ #if NO_INVISIBLE_LEVELS
+ if (ppr)
+ *ppr =3D (ref_packed *)obj;
+ #endif
}
make_array(parr, attrs | mem->space, num_refs, obj);
***************
*** 274,277 ****
--- 287,294 ----
if ((obj_header_t *) obj =3D=3D mem->cc.rcur) {
/* Deallocate the entire refs object. */
+ #if NO_INVISIBLE_LEVELS
+ if ((gs_memory_t *)mem !=3D mem->stable_memory)
+ alloc_save_remove(mem, (ref_packed *)obj, "gs_free_ref_array");
+ #endif
gs_free_object((gs_memory_t *) mem, obj, cname);
mem->cc.rcur =3D 0;
***************
*** 303,306 ****
--- 320,327 ----
ialloc_trace_space(mem), client_name_string(cname),
num_refs, (ulong) obj);
+ #if NO_INVISIBLE_LEVELS
+ if ((gs_memory_t *)mem !=3D mem->stable_memory)
+ alloc_save_remove(mem, (ref_packed *)obj, "gs_free_ref_array");
+ #endif
alloc_free_chunk(cl.cp, mem);
return;
=20
=20
=20
*** F:\SVN-GS\HEAD\gs\src\idosave.h Wed Mar 15 15:04:33 2006
--- files\gs\src\idosave.h Wed Apr 12 11:34:26 2006
***************
*** 34,37 ****
--- 34,43 ----
int alloc_save_change_in(gs_ref_memory_t *mem, const ref *pcont,
ref_packed *ptr, client_name_t cname);
+ #if NO_INVISIBLE_LEVELS
+ /* Remove an AC_OFFSET_ALLOCATED element. */
+ void alloc_save_remove(gs_ref_memory_t *mem, ref_packed *obj, =
client_name_t cname);
+ /* Allocate a structure for recording an allocation event. */
+ int alloc_save_change_alloc(gs_ref_memory_t *mem, client_name_t cname, =
ref_packed ***ppr);
+ #endif
=20
#endif /* idosave_INCLUDED */
=20
=20
=20
*** F:\SVN-GS\HEAD\gs\src\igc.c Wed Mar 15 15:04:36 2006
--- files\gs\src\igc.c Fri Apr 14 11:06:30 2006
***************
*** 149,152 ****
--- 149,153 ----
# define end_phase(str) DO_NOTHING
#endif /* DEBUG */
+=20
void
gs_gc_reclaim(vm_spaces * pspaces, bool global)
***************
*** 372,375 ****
--- 373,390 ----
end_phase("finish trace");
}
+=20
+ #if NO_INVISIBLE_LEVELS
+ /* Filter save change lists with removing elements,
+ which point to unmarked blocks of refs. */
+ {
+ int i;
+=20
+ for_collected_spaces(i) {
+ gs_ref_memory_t *mem =3D space_memories[i];
+=20
+ alloc_save__filter_changes(mem);
+ }
+ }
+ #endif
/* Clear marks and relocation in spaces that are only being =
traced. */
/* We have to clear the marks first, because we want the */
=20
=20
=20
*** F:\SVN-GS\HEAD\gs\src\igcref.c Wed Mar 15 15:04:41 2006
--- files\gs\src\igcref.c Fri Apr 14 11:04:40 2006
***************
*** 34,37 ****
--- 34,40 ----
/* Forward references */
ptr_proc_reloc(igc_reloc_ref_ptr, ref_packed);
+ #if NO_INVISIBLE_LEVELS
+ ptr_proc_reloc(igc_reloc_ref_ptr_nocheck, ref_packed);
+ #endif
refs_proc_reloc(igc_reloc_refs);
=20
***************
*** 547,550 ****
--- 550,664 ----
}
=20
+ #if NO_INVISIBLE_LEVELS
+ /* Relocate a pointer to a ref. */
+ /* See gsmemory.h for why the argument is const and the result is not. =
*/
+ ref_packed *
+ igc_reloc_ref_ptr_nocheck(const ref_packed * prp, gc_state_t *gcst)
+ {
+ /*
+ * Search forward for relocation. This algorithm is intrinsically =
very
+ * inefficient; we hope eventually to replace it with a better =
one.
+ */
+ const ref_packed *rp =3D prp;
+ uint dec =3D 0;
+ #ifdef ALIGNMENT_ALIASING_BUG
+ const ref *rpref;
+ # define RP_REF(rp) (rpref =3D (const ref *)rp, rpref)
+ #else
+ # define RP_REF(rp) ((const ref *)rp)
+ #endif
+ for (;;) {
+=20
+ if (r_is_packed(rp)) {
+ /*
+ * Normally, an unmarked packed ref will be an
+ * integer whose value is the amount of relocation.
+ * However, the relocation value might have been
+ * too large to fit. If this is the case, for
+ * each such unmarked packed ref we pass over,
+ * we have to decrement the final relocation.
+ */
+ rputc((*rp & lp_mark ? '1' : '0'));
+ if (!(*rp & lp_mark)) {
+ if (*rp !=3D pt_tag(pt_integer) + packed_max_value) {
+ /* This is a stored relocation value. */
+ rputc('\n');
+ rp =3D print_reloc(prp, "ref",
+ (const ref_packed *)
+ ((const char *)prp -
+ (*rp & packed_value_mask) + dec));
+ break;
+ }
+ /*
+ * We know this is the first of an aligned block
+ * of packed refs. Skip over the entire block,
+ * decrementing the final relocation.
+ */
+ dec +=3D sizeof(ref_packed) * align_packed_per_ref;
+ rp +=3D align_packed_per_ref;
+ } else
+ rp++;
+ continue;
+ }
+ if (!ref_type_uses_size_or_null(r_type(RP_REF(rp)))) {
+ /* reloc is in r_size */
+ rputc('\n');
+ rp =3D print_reloc(prp, "ref",
+ (const ref_packed *)
+ (r_size(RP_REF(rp)) =3D=3D 0 ? prp :
+ (const ref_packed *)((const char *)prp -
+ r_size(RP_REF(rp)) + dec)));
+ break;
+ }
+ rputc('u');
+ rp +=3D packed_per_ref;
+ }
+ ret_rp:
+ /* Use a severely deprecated pun to remove the const property. */
+ {
+ union { const ref_packed *r; ref_packed *w; } u;
+=20
+ u.r =3D rp;
+ return u.w;
+ }
+ #undef RP_REF
+ }
+ ref_packed *
+ igc_reloc_ref_ptr(const ref_packed * prp, gc_state_t *gcst)
+ {
+ /*
+ * Search forward for relocation. This algorithm is intrinsically =
very
+ * inefficient; we hope eventually to replace it with a better =
one.
+ */
+ const ref_packed *rp =3D prp;
+ #ifdef ALIGNMENT_ALIASING_BUG
+ const ref *rpref;
+ # define RP_REF(rp) (rpref =3D (const ref *)rp, rpref)
+ #else
+ # define RP_REF(rp) ((const ref *)rp)
+ #endif
+ /*
+ * Iff this pointer points into a space that wasn't traced,
+ * the referent won't be marked. In this case, we shouldn't
+ * do any relocation. Check for this first.
+ */
+ if (r_is_packed(rp)) {
+ if (!r_has_pmark(rp))
+ goto ret_rp;
+ } else {
+ if (!r_has_attr(RP_REF(rp), l_mark))
+ goto ret_rp;
+ }
+ return igc_reloc_ref_ptr_nocheck(prp, gcst);
+ ret_rp:
+ /* Use a severely deprecated pun to remove the const property. */
+ {
+ union { const ref_packed *r; ref_packed *w; } u;
+=20
+ u.r =3D rp;
+ return u.w;
+ }
+ }
+ #else
/* Relocate a pointer to a ref. */
/* See gsmemory.h for why the argument is const and the result is not. =
*/
***************
*** 631,634 ****
--- 745,749 ----
}
}
+ #endif
=20
/* ------ Compaction phase ------ */
***************
*** 644,649 ****
--- 759,772 ----
uint new_size;
=20
+ /* The next switch controls an optimization=20
+ for the loop termination condition.
+ It was useful during the development,
+ when some assumptions were temporary wrong.
+ We keep it for records. */
+ #define LAST_ELEM_MAY_BE_MARKED (0 && NO_INVISIBLE_LEVELS)
+=20
src =3D (ref_packed *) (pre + 1);
end =3D (ref_packed *) ((byte *) src + size);
+ #if LAST_ELEM_MAY_BE_MARKED
/*
* We know that a block of refs always ends with an unmarked
***************
*** 651,654 ****
--- 774,784 ----
* of the block when we see one of those.
*/
+ #else
+ /*
+ * We know that a block of refs always ends with a
+ * full-size ref, so we only need to check for reaching the end
+ * of the block when we see one of those.
+ */
+ #endif
if (dpre =3D=3D pre) /* Loop while we don't need to copy. */
for (;;) {
***************
*** 668,671 ****
--- 798,810 ----
r_clear_attrs(pref, l_mark);
src +=3D packed_per_ref;
+ #if LAST_ELEM_MAY_BE_MARKED
+ /* The last (the extra) ref may be marked from=20
+ alloc_change_t::offset=3D=3DAC_OFFSET_ALLOCATED,
+ if the extra ref ends an empty ref array. */
+ if (src >=3D end) {
+ src -=3D packed_per_ref;
+ break;
+ }
+ #endif
}
} else
***************
*** 692,697 ****
r_clear_attrs(&rtemp, l_mark);
ref_assign_inline((ref *) dest, &rtemp);
- dest +=3D packed_per_ref;
src +=3D packed_per_ref;
} else { /* check for end of block */
src +=3D packed_per_ref;
--- 831,843 ----
r_clear_attrs(&rtemp, l_mark);
ref_assign_inline((ref *) dest, &rtemp);
src +=3D packed_per_ref;
+ #if LAST_ELEM_MAY_BE_MARKED
+ /* The last (the extra) ref may be marked from=20
+ alloc_change_t::offset=3D=3DAC_OFFSET_ALLOCATED,
+ if the extra ref ends an empty ref array. */
+ if (src >=3D end)
+ break;
+ #endif
+ dest +=3D packed_per_ref;
} else { /* check for end of block */
src +=3D packed_per_ref;
***************
*** 701,704 ****
--- 847,851 ----
}
}
+ #undef LAST_ELEM_MAY_BE_MARKED
new_size =3D (byte *) dest - (byte *) (dpre + 1) + sizeof(ref);
#ifdef DEBUG
=20
=20
=20
*** F:\SVN-GS\HEAD\gs\src\isave.c Wed Mar 15 15:04:49 2006
--- files\gs\src\isave.c Fri Apr 14 11:21:58 2006
***************
*** 28,34 ****
#include "store.h" /* for ref_assign */
#include "ivmspace.h"
#include "gsutil.h" /* gs_next_ids prototype */
=20
-=20
/* Structure descriptor */
private_st_alloc_save();
--- 28,36 ----
#include "store.h" /* for ref_assign */
#include "ivmspace.h"
+ #if NO_INVISIBLE_LEVELS
+ #include "igc.h"
+ #endif
#include "gsutil.h" /* gs_next_ids prototype */
=20
/* Structure descriptor */
private_st_alloc_save();
***************
*** 154,157 ****
--- 156,164 ----
}
=20
+ #if NO_INVISIBLE_LEVELS
+ /* A link to igcref.c . */
+ ptr_proc_reloc(igc_reloc_ref_ptr_nocheck, ref_packed);
+ #endif
+=20
/*
* Structure for saved change chain for save/restore. Because of the
***************
*** 166,169 ****
--- 173,179 ----
#define AC_OFFSET_STATIC (-2) /* static object */
#define AC_OFFSET_REF (-1) /* dynamic ref */
+ #if NO_INVISIBLE_LEVELS
+ #define AC_OFFSET_ALLOCATED (-3) /* a newly allocated ref array */
+ #endif
short offset; /* if >=3D 0, offset within struct */
};
***************
*** 186,189 ****
--- 196,207 ----
ENUM_RETURN((byte *) ptr->where - ptr->offset);
else
+ if (ptr->offset !=3D AC_OFFSET_ALLOCATED)
+ ENUM_RETURN_REF(ptr->where);
+ else {
+ /* Don't enumerate ptr->where, because it=20
+ needs a special processing with=20
+ alloc_save__filter_changes. */
+ ENUM_RETURN(0);
+ }
ENUM_RETURN_REF(ptr->where);
case 2:
***************
*** 199,202 ****
--- 217,240 ----
RELOC_REF_PTR_VAR(ptr->where);
break;
+ #if NO_INVISIBLE_LEVELS
+ case AC_OFFSET_ALLOCATED:
+ /* We know that ptr->where may point to an unmarked object
+ because change_enum_ptrs skipped it,
+ and we know it always points to same space=20
+ because we took a special care when calling =
alloc_save_change_alloc.
+ Therefore we must skip the check for the mark,
+ which would happen if we call the regular relocation function
+ igc_reloc_ref_ptr from RELOC_REF_PTR_VAR.=20
+ Calling igc_reloc_ref_ptr_nocheck instead. */
+ { /* A sanity check. */
+ obj_header_t *pre =3D (obj_header_t *)ptr->where - 1, *pre1 =3D 0;
+=20
+ if (pre->o_type !=3D &st_refs)
+ pre1->o_type =3D 0; /* issue a segfault. */
+ }
+ if (ptr->where !=3D 0 && !gcst->relocating_untraced)
+ ptr->where =3D igc_reloc_ref_ptr_nocheck(ptr->where, gcst);
+ break;
+ #endif
default:
{
***************
*** 250,255 ****
private int restore_resources(alloc_save_t *, gs_ref_memory_t *);
private void restore_free(gs_ref_memory_t *);
! private long save_set_new(gs_ref_memory_t *, bool);
! private void save_set_new_changes(gs_ref_memory_t *, bool);
=20
/* Initialize the save/restore machinery. */
--- 288,296 ----
private int restore_resources(alloc_save_t *, gs_ref_memory_t *);
private void restore_free(gs_ref_memory_t *);
! private long save_set_new(gs_ref_memory_t *, bool, bool);
! private void save_set_new_changes(gs_ref_memory_t *, bool, bool);
! #if NO_INVISIBLE_LEVELS
! private bool check_l_mark(void *obj);
! #endif
=20
/* Initialize the save/restore machinery. */
***************
*** 336,341 ****
/* and ones in objects allocated since the last save. */
if (lmem->save_level > 1) {
! long scanned =3D save_set_new(&lsave->state, false);
=20
if ((lsave->state.total_scanned +=3D scanned) > max_repeated_scan) {
/* Do a second, invisible save. */
--- 377,383 ----
/* and ones in objects allocated since the last save. */
if (lmem->save_level > 1) {
! long scanned =3D save_set_new(&lsave->state, false, true);
=20
+ #if !NO_INVISIBLE_LEVELS
if ((lsave->state.total_scanned +=3D scanned) > max_repeated_scan) {
/* Do a second, invisible save. */
***************
*** 365,368 ****
--- 407,413 ----
}
}
+ #else
+ (void)scanned;
+ #endif
}
alloc_set_in_save(dmem);
***************
*** 484,487 ****
--- 529,611 ----
}
=20
+ #if NO_INVISIBLE_LEVELS
+ /* Allocate a structure for recording an allocation event. */
+ int
+ alloc_save_change_alloc(gs_ref_memory_t *mem, client_name_t cname, =
ref_packed ***ppr)
+ {
+ register alloc_change_t *cp;
+=20
+ if (mem->new_mask =3D=3D 0)
+ return 0; /* no saving */
+ cp =3D gs_alloc_struct((gs_memory_t *)mem, alloc_change_t,
+ &st_alloc_change, "alloc_save_change");
+ if (cp =3D=3D 0)
+ return_error(e_VMerror);
+ cp->next =3D mem->changes;
+ cp->where =3D 0;
+ cp->offset =3D AC_OFFSET_ALLOCATED;
+ make_null(&cp->contents);
+ mem->changes =3D cp;
+ *ppr =3D &cp->where;
+ return 1;
+ }
+=20
+ /* Remove an AC_OFFSET_ALLOCATED element. */
+ void
+ alloc_save_remove(gs_ref_memory_t *mem, ref_packed *obj, client_name_t =
cname)
+ {
+ alloc_change_t **cpp =3D &mem->changes;
+ =20
+ for (; *cpp !=3D NULL;) {
+ alloc_change_t *cp =3D *cpp;
+=20
+ if (cp->offset =3D=3D AC_OFFSET_ALLOCATED && cp->where =3D=3D obj) {
+ if (mem->scan_limit =3D=3D cp)
+ mem->scan_limit =3D cp->next;
+ *cpp =3D cp->next;
+ gs_free_object((gs_memory_t *)mem, cp, "alloc_save_remove");
+ } else
+ cpp =3D &(*cpp)->next;
+ }
+ }
+=20
+ /* Filter save change lists. */
+ private inline void
+ alloc_save__filter_changes_in_space(gs_ref_memory_t *mem)
+ {
+ /* This is a special function, which is called
+ from the garbager after setting marks and before collecting
+ unused space. Therefore it just resets marks for
+ elements being released instead releasing them really. */
+ alloc_change_t **cpp =3D &mem->changes;
+ =20
+ for (; *cpp !=3D NULL; ) {
+ alloc_change_t *cp =3D *cpp;
+=20
+ if (cp->offset =3D=3D AC_OFFSET_ALLOCATED && =
!check_l_mark(cp->where)) {
+ obj_header_t *pre =3D (obj_header_t *)cp - 1;
+=20
+ *cpp =3D cp->next;
+ cp->where =3D 0;
+ if (mem->scan_limit =3D=3D cp)
+ mem->scan_limit =3D cp->next;
+ o_set_unmarked(pre);
+ } else
+ cpp =3D &(*cpp)->next;
+ }
+ }
+=20
+ /* Filter save change lists. */
+ void
+ alloc_save__filter_changes(gs_ref_memory_t *memory)
+ {
+ gs_ref_memory_t *mem =3D memory;
+=20
+ for (; mem; mem =3D &mem->saved->state)
+ alloc_save__filter_changes_in_space(mem);
+ }
+=20
+ #endif
+=20
/* Return (the id of) the innermost externally visible save object, */
/* i.e., the innermost save with a non-zero ID. */
***************
*** 694,698 ****
alloc_set_not_in_save(dmem);
} else { /* Set the l_new attribute in all slots that are now =
new. */
! save_set_new(mem, true);
}
=20
--- 818,822 ----
alloc_set_not_in_save(dmem);
} else { /* Set the l_new attribute in all slots that are now =
new. */
! save_set_new(mem, true, false);
}
=20
***************
*** 720,723 ****
--- 844,852 ----
}
#endif
+ #if NO_INVISIBLE_LEVELS
+ if (cp->offset =3D=3D AC_OFFSET_ALLOCATED)
+ DO_NOTHING;
+ else
+ #endif
if (r_is_packed(&cp->contents))
*cp->where =3D *(ref_packed *) & cp->contents;
***************
*** 891,895 ****
alloc_change_t *chp =3D mem->changes;
=20
! save_set_new(&sprev->state, true);
/* Concatenate the changes chains. */
if (chp =3D=3D 0)
--- 1020,1024 ----
alloc_change_t *chp =3D mem->changes;
=20
! save_set_new(&sprev->state, true, false);
/* Concatenate the changes chains. */
if (chp =3D=3D 0)
***************
*** 904,908 ****
} else {
forget_changes(mem);
! save_set_new(mem, false);
file_forget_save(mem);
combine_space(mem); /* combine memory */
--- 1033,1037 ----
} else {
forget_changes(mem);
! save_set_new(mem, false, false);
file_forget_save(mem);
combine_space(mem); /* combine memory */
***************
*** 912,916 ****
if (mem !=3D save->space_local && mem->saved !=3D 0) {
forget_changes(mem);
! save_set_new(mem, false);
file_forget_save(mem);
combine_space(mem);
--- 1041,1045 ----
if (mem !=3D save->space_local && mem->saved !=3D 0) {
forget_changes(mem);
! save_set_new(mem, false, false);
file_forget_save(mem);
combine_space(mem);
***************
*** 1015,1018 ****
--- 1144,1152 ----
=20
if_debug1('U', "[U]forgetting change 0x%lx\n", (ulong) chp);
+ #if NO_INVISIBLE_LEVELS
+ if (chp->offset =3D=3D AC_OFFSET_ALLOCATED)
+ DO_NOTHING;
+ else
+ #endif
if (!r_is_packed(prp))
r_clear_attrs((ref *) prp, l_new);
***************
*** 1043,1071 ****
}
=20
! /* ------ Internal routines ------ */
!=20
! /* Set or reset the l_new attribute in every relevant slot. */
! /* This includes every slot on the current change chain, */
! /* and every (ref) slot allocated at this save level. */
! /* Return the number of bytes of data scanned. */
! private long
! save_set_new(gs_ref_memory_t * mem, bool to_new)
{
! long scanned =3D 0;
!=20
! /* Handle the change chain. */
! save_set_new_changes(mem, to_new);
!=20
! /* Handle newly allocated ref objects. */
! SCAN_MEM_CHUNKS(mem, cp) {
! if (cp->has_refs) {
! bool has_refs =3D false;
!=20
! SCAN_CHUNK_OBJECTS(cp)
! DO_ALL
! if_debug3('U', "[U]set_new scan(0x%lx(%u), %d)\n",
! (ulong) pre, size, to_new);
! if (pre->o_type =3D=3D &st_refs) {
! /* These are refs, scan them. */
ref_packed *prp =3D (ref_packed *) (pre + 1);
ref_packed *next =3D (ref_packed *) ((char *)prp + size);
--- 1177,1185 ----
}
=20
! private inline uint
! mark_allocated(void *obj, bool to_new)
{ =20
! obj_header_t *pre =3D (obj_header_t *)obj - 1;
! uint size =3D pre_obj_contents_size(pre);
ref_packed *prp =3D (ref_packed *) (pre + 1);
ref_packed *next =3D (ref_packed *) ((char *)prp + size);
***************
*** 1077,1084 ****
#endif
=20
! if_debug2('U', "[U]refs 0x%lx to 0x%lx\n",
! (ulong) prp, (ulong) next);
! has_refs =3D true;
! scanned +=3D size;
/* We know that every block of refs ends with */
/* a full-size ref, so we only need the end check */
--- 1191,1201 ----
#endif
=20
! if (pre->o_type !=3D &st_refs) {
! /* Must not happen. Can't continue. Emit a crash. */
! int i =3D *(int *)0;
!=20
! mark_allocated((void *)i, false); /* an untrivial use of i=20
! against code optimization. */
! }
/* We know that every block of refs ends with */
/* a full-size ref, so we only need the end check */
***************
*** 1106,1109 ****
--- 1223,1292 ----
}
#undef RP_REF
+ return size;
+ }
+=20
+ #if NO_INVISIBLE_LEVELS
+ /* Check if a block contains refs marked by garbager. */
+ private bool
+ check_l_mark(void *obj)
+ { =20
+ obj_header_t *pre =3D (obj_header_t *)obj - 1;
+ uint size =3D pre_obj_contents_size(pre);
+ ref_packed *prp =3D (ref_packed *) (pre + 1);
+ ref_packed *next =3D (ref_packed *) ((char *)prp + size);
+ #ifdef ALIGNMENT_ALIASING_BUG
+ ref *rpref;
+ # define RP_REF(rp) (rpref =3D (ref *)rp, rpref)
+ #else
+ # define RP_REF(rp) ((ref *)rp)
+ #endif
+=20
+ /* We know that every block of refs ends with */
+ /* a full-size ref, so we only need the end check */
+ /* when we encounter one of those. */
+ while (1) {
+ if (r_is_packed(prp)) {
+ if (r_has_pmark(prp))
+ return true;
+ prp++;
+ } else {
+ if (r_has_attr(RP_REF(prp), l_mark))
+ return true;
+ prp +=3D packed_per_ref;
+ if (prp >=3D next)
+ return false;
+ }
+ }
+ #undef RP_REF
+ }
+ #endif
+=20
+ /* Set or reset the l_new attribute in every relevant slot. */
+ /* This includes every slot on the current change chain, */
+ /* and every (ref) slot allocated at this save level. */
+ /* Return the number of bytes of data scanned. */
+ private long
+ save_set_new(gs_ref_memory_t * mem, bool to_new, bool set_limit)
+ {
+ long scanned =3D 0;
+=20
+ /* Handle the change chain. */
+ save_set_new_changes(mem, to_new, set_limit);
+=20
+ #if !NO_INVISIBLE_LEVELS
+ /* Handle newly allocated ref objects. */
+ SCAN_MEM_CHUNKS(mem, cp) {
+ if (cp->has_refs) {
+ bool has_refs =3D false;
+=20
+ SCAN_CHUNK_OBJECTS(cp)
+ DO_ALL
+ if_debug3('U', "[U]set_new scan(0x%lx(%u), %d)\n",
+ (ulong) pre, size, to_new);
+ if (pre->o_type =3D=3D &st_refs) {
+ /* These are refs, scan them. */
+ ref_packed *prp =3D (ref_packed *) (pre + 1);
+=20
+ scanned +=3D mark_allocated(prp, to_new);
} else
scanned +=3D sizeof(obj_header_t);
***************
*** 1115,1118 ****
--- 1298,1302 ----
if_debug2('u', "[u]set_new (%s) scanned %ld\n",
(to_new ? "restore" : "save"), scanned);
+ #endif
return scanned;
}
***************
*** 1120,1129 ****
/* Set or reset the l_new attribute on the changes chain. */
private void
! save_set_new_changes(gs_ref_memory_t * mem, bool to_new)
{
register alloc_change_t *chp =3D mem->changes;
register uint new =3D (to_new ? l_new : 0);
=20
for (; chp; chp =3D chp->next) {
ref_packed *prp =3D chp->where;
=20
--- 1304,1323 ----
/* Set or reset the l_new attribute on the changes chain. */
private void
! save_set_new_changes(gs_ref_memory_t * mem, bool to_new, bool =
set_limit)
{
register alloc_change_t *chp =3D mem->changes;
register uint new =3D (to_new ? l_new : 0);
+ #if NO_INVISIBLE_LEVELS
+ long scanned =3D mem->total_scanned;
+ #endif
=20
for (; chp; chp =3D chp->next) {
+ #if NO_INVISIBLE_LEVELS
+ if (chp->offset =3D=3D AC_OFFSET_ALLOCATED) {
+ if (chp->where !=3D 0)
+ scanned +=3D mark_allocated((void *)chp->where, to_new);
+ } else
+ #endif
+ {
ref_packed *prp =3D chp->where;
=20
***************
*** 1137,1139 ****
--- 1331,1347 ----
}
}
+ #if NO_INVISIBLE_LEVELS
+ if (mem->scan_limit =3D=3D chp)
+ break;
+ #endif
+ }
+ #if NO_INVISIBLE_LEVELS
+ if (set_limit) {
+ if (scanned >=3D max_repeated_scan) {
+ mem->scan_limit =3D mem->changes;
+ mem->total_scanned =3D 0;
+ } else
+ mem->total_scanned =3D scanned;
+ }
+ #endif
}
=20
=20
=20
*** F:\SVN-GS\HEAD\gs\src\isave.h Wed Mar 15 15:04:49 2006
--- files\gs\src\isave.h Thu Apr 13 13:13:10 2006
***************
*** 92,95 ****
--- 92,97 ----
/* Release all memory -- like doing a restore "past the bottom". */
int alloc_restore_all(gs_dual_memory_t *);
+ /* Filter save change lists. */
+ void alloc_save__filter_changes(gs_ref_memory_t *mem);
=20
/* ------ Internals ------ */
=20
------=_NextPart_000_0008_01C65FB7.CD1001B0
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
gs-code-review mailing list
[email protected]
http://www.ghostscript.com/mailman/listinfo/gs-code-review
------=_NextPart_000_0008_01C65FB7.CD1001B0--