writefile: remove SDNA last-hit, optimize DNA reconstruct

- Move last-hit index out of SDNA struct
  (allows for access by multiple threads).
- Replace O(n^2) search with hash lookup in DNA reconstruction.
This commit is contained in:
Campbell Barton 2016-07-12 11:48:04 +10:00
parent 7212ebd09f
commit 0b3183d13c
4 changed files with 91 additions and 79 deletions

@ -1844,7 +1844,7 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
/* ********** END OLD POINTERS ****************** */
/* ********** READ FILE ****************** */
static void switch_endian_structs(struct SDNA *filesdna, BHead *bhead)
static void switch_endian_structs(const struct SDNA *filesdna, BHead *bhead)
{
int blocksize, nblocks;
char *data;

@ -79,10 +79,13 @@ struct SDNA *DNA_sdna_from_data(
bool do_endian_swap, bool data_alloc);
void DNA_sdna_free(struct SDNA *sdna);
int DNA_struct_find_nr(struct SDNA *sdna, const char *str);
void DNA_struct_switch_endian(struct SDNA *oldsdna, int oldSDNAnr, char *data);
char *DNA_struct_get_compareflags(struct SDNA *sdna, struct SDNA *newsdna);
void *DNA_struct_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data);
int DNA_struct_find_nr_ex(const struct SDNA *sdna, const char *str, unsigned int *index_last);
int DNA_struct_find_nr(const struct SDNA *sdna, const char *str);
void DNA_struct_switch_endian(const struct SDNA *oldsdna, int oldSDNAnr, char *data);
char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA*newsdna);
void *DNA_struct_reconstruct(
const struct SDNA *newsdna, const struct SDNA *oldsdna,
char *compflags, int oldSDNAnr, int blocks, void *data);
int DNA_elem_array_size(const char *str);
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);

@ -35,12 +35,12 @@
#
#
typedef struct SDNA {
const char *data; /* full copy of 'encoded' data */
const char *data; /* full copy of 'encoded' data (when data_alloc is set, otherwise borrowed). */
int datalen; /* length of data */
bool data_alloc;
int nr_names; /* total number of struct members */
const char **names; /* struct member names */
const char **names; /* struct member names */
int pointerlen; /* size of a pointer in bytes */
@ -57,11 +57,6 @@ typedef struct SDNA {
struct GHash *structs_map; /* ghash for faster lookups,
* requires WITH_DNA_GHASH to be used for now */
/* wrong place for this really, its a simple
* cache for findstruct_nr.
*/
int lastfind;
} SDNA;
#

@ -39,6 +39,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
@ -279,38 +280,17 @@ static void printstruct(SDNA *sdna, short strnr)
}
#endif
/**
* Returns a pointer to the start of the struct info for the struct with the specified name.
*/
static short *findstruct_name(SDNA *sdna, const char *str)
{
int a;
short *sp = NULL;
for (a = 0; a < sdna->nr_structs; a++) {
sp = sdna->structs[a];
if (strcmp(sdna->types[sp[0]], str) == 0) {
return sp;
}
}
return NULL;
}
/**
* Returns the index of the struct info for the struct with the specified name.
*/
int DNA_struct_find_nr(SDNA *sdna, const char *str)
int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last)
{
const short *sp = NULL;
if (sdna->lastfind < sdna->nr_structs) {
sp = sdna->structs[sdna->lastfind];
if (*index_last < sdna->nr_structs) {
sp = sdna->structs[*index_last];
if (strcmp(sdna->types[sp[0]], str) == 0) {
return sdna->lastfind;
return *index_last;
}
}
@ -323,7 +303,7 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str)
if (index_p) {
a = GET_INT_FROM_POINTER(*index_p);
sdna->lastfind = a;
*index_last = a;
}
else {
a = -1;
@ -339,7 +319,7 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str)
sp = sdna->structs[a];
if (strcmp(sdna->types[sp[0]], str) == 0) {
sdna->lastfind = a;
*index_last = a;
return a;
}
}
@ -348,6 +328,12 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str)
#endif
}
int DNA_struct_find_nr(const SDNA *sdna, const char *str)
{
unsigned int index_last_dummy = UINT_MAX;
return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy);
}
/* ************************* END DIV ********************** */
/* ************************* READ DNA ********************** */
@ -358,16 +344,21 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str)
static void init_structDNA(SDNA *sdna, bool do_endian_swap)
{
int *data, *verg, gravity_fix = -1;
intptr_t nr;
short *sp;
char str[8], *cp;
char str[8];
verg = (int *)str;
data = (int *)sdna->data;
strcpy(str, "SDNA");
if (*data == *verg) {
if (*data != *verg) {
printf("SDNA error in SDNA file\n");
return;
}
else {
intptr_t nr;
char *cp;
data++;
/* load names array */
@ -515,11 +506,45 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
nr++;
}
}
{
/* second part of gravity problem, setting "gravity" type to void */
if (gravity_fix > -1) {
for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
if (strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0)
sp[10] = SDNA_TYPE_VOID;
}
}
}
#ifdef WITH_DNA_GHASH
{
/* create a ghash lookup to speed up */
sdna->structs_map = BLI_ghash_str_new_ex("init_structDNA gh", sdna->nr_structs);
for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr));
}
}
#endif
/* Calculate 'sdna->pointerlen' */
{
intptr_t nr = DNA_struct_find_nr(sdna, "ListBase");
/* should never happen, only with corrupt file for example */
if (UNLIKELY(nr == -1)) {
printf("ListBase struct error! Not found.\n");
exit(1);
}
/* finally pointerlen: use struct ListBase to test it, never change the size of it! */
sp = findstruct_name(sdna, "ListBase");
sp = sdna->structs[nr];
/* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */
sdna->pointerlen = sdna->typelens[sp[0]] / 2;
if (sp[1] != 2 || (sdna->pointerlen != 4 && sdna->pointerlen != 8)) {
@ -527,25 +552,6 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap)
exit(1);
/* well, at least sizeof(ListBase) is error proof! (ton) */
}
/* second part of gravity problem, setting "gravity" type to void */
if (gravity_fix > -1) {
for (nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
if (strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0)
sp[10] = SDNA_TYPE_VOID;
}
}
#ifdef WITH_DNA_GHASH
/* create a ghash lookup to speed up */
sdna->structs_map = BLI_ghash_str_new_ex("init_structDNA gh", sdna->nr_structs);
for (nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr));
}
#endif
}
}
@ -557,8 +563,6 @@ SDNA *DNA_sdna_from_data(
bool do_endian_swap, bool data_alloc)
{
SDNA *sdna = MEM_mallocN(sizeof(*sdna), "sdna");
sdna->lastfind = 0;
sdna->datalen = datalen;
if (data_alloc) {
@ -623,7 +627,7 @@ static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structn
* - 1 Struct is the same (can be loaded with straight memory copy after any necessary endian conversion)
* - 2 Struct is different in some way (needs to be copied/converted field by field)
*/
char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna)
char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna)
{
int a, b;
const short *sp_old, *sp_new;
@ -640,14 +644,19 @@ char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna)
/* we check all structs in 'oldsdna' and compare them with
* the structs in 'newsdna'
*/
unsigned int newsdna_index_last = 0;
for (a = 0; a < oldsdna->nr_structs; a++) {
sp_old = oldsdna->structs[a];
/* search for type in cur */
sp_new = findstruct_name(newsdna, oldsdna->types[sp_old[0]]);
if (sp_new) {
int sp_new_index = DNA_struct_find_nr_ex(newsdna, oldsdna->types[sp_old[0]], &newsdna_index_last);
/* The next indices will almost always match */
newsdna_index_last++;
if (sp_new_index != -1) {
sp_new = newsdna->structs[sp_new_index];
/* initial assumption */
compflags[a] = SDNA_CMP_NOT_EQUAL;
@ -1037,8 +1046,8 @@ static void reconstruct_elem(
* \param cur Where to put converted struct contents
*/
static void reconstruct_struct(
SDNA *newsdna,
SDNA *oldsdna,
const SDNA *newsdna,
const SDNA *oldsdna,
const char *compflags,
int oldSDNAnr,
@ -1056,6 +1065,10 @@ static void reconstruct_struct(
char *cpo, *cpc;
const char *name, *nameo;
unsigned int oldsdna_index_last = UINT_MAX;
unsigned int cursdna_index_last = UINT_MAX;
if (oldSDNAnr == -1) return;
if (curSDNAnr == -1) return;
@ -1090,8 +1103,8 @@ static void reconstruct_struct(
cpo = find_elem(oldsdna, type, name, spo, data, &sppo);
if (cpo) {
oldSDNAnr = DNA_struct_find_nr(oldsdna, type);
curSDNAnr = DNA_struct_find_nr(newsdna, type);
oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last);
curSDNAnr = DNA_struct_find_nr_ex(newsdna, type, &cursdna_index_last);
/* array! */
mul = DNA_elem_array_size(name);
@ -1132,7 +1145,7 @@ static void reconstruct_struct(
* \param oldSDNAnr Index of struct info within oldsdna
* \param data Struct data
*/
void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data)
{
/* Recursive!
* If element is a struct, call recursive.
@ -1141,6 +1154,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
const short *spo, *spc;
char *cur;
const char *type, *name;
unsigned int oldsdna_index_last = UINT_MAX;
if (oldSDNAnr == -1) return;
firststructtypenr = *(oldsdna->structs[0]);
@ -1165,7 +1179,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
/* where does the old data start (is there one?) */
char *cpo = find_elem(oldsdna, type, name, spo, data, NULL);
if (cpo) {
oldSDNAnr = DNA_struct_find_nr(oldsdna, type);
oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last);
mul = DNA_elem_array_size(name);
elena = elen / mul;
@ -1223,7 +1237,9 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
* \param data Array of struct data
* \return An allocated reconstructed struct
*/
void *DNA_struct_reconstruct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data)
void *DNA_struct_reconstruct(
const SDNA *newsdna, const SDNA *oldsdna,
char *compflags, int oldSDNAnr, int blocks, void *data)
{
int a, curSDNAnr, curlen = 0, oldlen;
const short *spo, *spc;
@ -1263,7 +1279,6 @@ void *DNA_struct_reconstruct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int
*/
int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
const short * const spo = sdna->structs[SDNAnr];
const char * const cp = find_elem(sdna, vartype, name, spo, NULL, NULL);
@ -1273,7 +1288,6 @@ int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const ch
bool DNA_struct_elem_find(SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
if (SDNAnr != -1) {