summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordotdotisdead <dotdotisdead@a3eca27d-f21b-0410-9b4a-6511e771f64e>2007-01-20 21:31:07 +0000
committerdotdotisdead <dotdotisdead@a3eca27d-f21b-0410-9b4a-6511e771f64e>2007-01-20 21:31:07 +0000
commit46bc79f71df9953b6b3c8c079f4621054bec44e8 (patch)
treebcf4a9e53a66ef7d0b30b7f331f0f0ce0cd50e3a
parentcb71b68706e9ca39b3d98162610cf1b3726a294c (diff)
Changes to support -I IOPT_SIZE on the commandline. New support for unlimited instruction
buffer size set by -I 0. The default remains 4096.
-rwxr-xr-xxdelta3/xdelta3-main.h40
-rwxr-xr-xxdelta3/xdelta3-regtest.py12
-rwxr-xr-xxdelta3/xdelta3-test.h6
-rwxr-xr-xxdelta3/xdelta3.c134
-rwxr-xr-xxdelta3/xdelta3.h21
5 files changed, 143 insertions, 70 deletions
diff --git a/xdelta3/xdelta3-main.h b/xdelta3/xdelta3-main.h
index cada82b..44bd6e5 100755
--- a/xdelta3/xdelta3-main.h
+++ b/xdelta3/xdelta3-main.h
@@ -248,7 +248,7 @@ static int option_quiet = 0;
248static int option_level = 5; 248static int option_level = 5;
249static int option_use_appheader = 1; 249static int option_use_appheader = 1;
250static uint8_t* option_appheader = NULL; 250static uint8_t* option_appheader = NULL;
251static int option_use_secondary = /* until-standardized, leave this off */ 0; 251static int option_use_secondary = 0;
252static char* option_secondary = NULL; 252static char* option_secondary = NULL;
253static int option_use_checksum = 1; 253static int option_use_checksum = 1;
254static int option_use_altcodetable = 0; 254static int option_use_altcodetable = 0;
@@ -257,6 +257,7 @@ static int option_no_compress = 0;
257static int option_no_output = 0; /* go through the motions, but do not open or write output */ 257static int option_no_output = 0; /* go through the motions, but do not open or write output */
258static const char *option_source_filename = NULL; 258static const char *option_source_filename = NULL;
259 259
260static int option_iopt_size = XD3_DEFAULT_IOPT_SIZE;
260static usize_t option_winsize = XD3_DEFAULT_WINSIZE; 261static usize_t option_winsize = XD3_DEFAULT_WINSIZE;
261static usize_t option_srcwinsz = XD3_DEFAULT_SRCWINSZ; 262static usize_t option_srcwinsz = XD3_DEFAULT_SRCWINSZ;
262static int option_srcwinsz_set = 0; 263static int option_srcwinsz_set = 0;
@@ -2267,6 +2268,7 @@ main_input (xd3_cmd cmd,
2267 config.sec_data.ngroups = 1; 2268 config.sec_data.ngroups = 1;
2268 config.sec_addr.ngroups = 1; 2269 config.sec_addr.ngroups = 1;
2269 config.sec_inst.ngroups = 1; 2270 config.sec_inst.ngroups = 1;
2271 config.iopt_size = option_iopt_size;
2270 2272
2271 /* TODO: eliminate static variables. */ 2273 /* TODO: eliminate static variables. */
2272 do_not_lru = 0; 2274 do_not_lru = 0;
@@ -2553,12 +2555,22 @@ main_input (xd3_cmd cmd,
2553 { 2555 {
2554 if (IS_ENCODE (cmd) || cmd == CMD_DECODE) 2556 if (IS_ENCODE (cmd) || cmd == CMD_DECODE)
2555 { 2557 {
2556 int used_source = xd3_encoder_used_source (& stream); 2558 if (! option_quiet && IS_ENCODE (cmd))
2557
2558 if (! option_quiet && IS_ENCODE (cmd) && main_file_isopen (sfile) && ! used_source)
2559 { 2559 {
2560 XPR(NT "warning: input position %"Q"u no source copies\n", 2560 /* Warn when no source copies are found */
2561 stream.current_window * option_winsize); 2561 if (main_file_isopen (sfile) && ! xd3_encoder_used_source (& stream))
2562 {
2563 XPR(NT "warning: input position %"Q"u no source copies\n",
2564 stream.current_window * option_winsize);
2565 }
2566
2567 /* Warn about bad compression due to limited instruction buffer */
2568 if (stream.i_slots_used > stream.iopt_size)
2569 {
2570 XPR(NT "warning: input position %"Q"u overflowed instruction buffer, "
2571 "needed %u (vs. %u)\n",
2572 stream.current_window * option_winsize, stream.i_slots_used, stream.iopt_size);
2573 }
2562 } 2574 }
2563 2575
2564 if (option_verbose) 2576 if (option_verbose)
@@ -2723,7 +2735,7 @@ main (int argc, char **argv)
2723 main_file ifile; 2735 main_file ifile;
2724 main_file ofile; 2736 main_file ofile;
2725 main_file sfile; 2737 main_file sfile;
2726 static char *flags = "0123456789cdefhnqvDJNORTVs:B:C:E:F:L:O:P:M:W:A::S::"; 2738 static char *flags = "0123456789cdefhnqvDJNORTVs:B:C:E:F:I:L:O:P:M:W:A::S::";
2727 int my_optind; 2739 int my_optind;
2728 char *my_optarg; 2740 char *my_optarg;
2729 char *my_optstr; 2741 char *my_optstr;
@@ -2925,6 +2937,13 @@ main (int argc, char **argv)
2925 goto exit; 2937 goto exit;
2926 } 2938 }
2927 break; 2939 break;
2940 case 'I':
2941 if ((ret = main_atou (my_optarg, & option_iopt_size, 0,
2942 0, 'I')))
2943 {
2944 goto exit;
2945 }
2946 break;
2928 case 'W': 2947 case 'W':
2929 if ((ret = main_atou (my_optarg, & option_winsize, XD3_ALLOCSIZE, 2948 if ((ret = main_atou (my_optarg, & option_winsize, XD3_ALLOCSIZE,
2930 XD3_HARDMAXWINSIZE, 'W'))) 2949 XD3_HARDMAXWINSIZE, 'W')))
@@ -3126,6 +3145,7 @@ main_help (void)
3126 P(RINT "memory options:\n"); 3145 P(RINT "memory options:\n");
3127 P(RINT " -B bytes source window size\n"); 3146 P(RINT " -B bytes source window size\n");
3128 P(RINT " -W bytes input window size\n"); 3147 P(RINT " -W bytes input window size\n");
3148 P(RINT " -I size instruction buffer size (0 = unlimited)\n");
3129 3149
3130 P(RINT "compression options:\n"); 3150 P(RINT "compression options:\n");
3131 P(RINT " -s source source file to copy from (if any)\n"); 3151 P(RINT " -s source source file to copy from (if any)\n");
@@ -3133,15 +3153,15 @@ main_help (void)
3133 P(RINT " -N disable small string-matching compression\n"); 3153 P(RINT " -N disable small string-matching compression\n");
3134 P(RINT " -D disable external decompression (encode/decode)\n"); 3154 P(RINT " -D disable external decompression (encode/decode)\n");
3135 P(RINT " -R disable external recompression (decode)\n"); 3155 P(RINT " -R disable external recompression (decode)\n");
3156 P(RINT " -n disable checksum (encode/decode)\n");
3157 P(RINT " -C soft config (encode, undocumented)\n");
3158 P(RINT " -A [apphead] disable/provide application header (encode)\n");
3136 3159
3137#if XD3_DEBUG > 0 3160#if XD3_DEBUG > 0
3138 P(RINT "developer options:\n"); 3161 P(RINT "developer options:\n");
3139 P(RINT " -A [apphead] disable/provide application header\n");
3140 P(RINT " -C soft config (see xdelta3-cfgs.h)\n");
3141 P(RINT " -J disable output (check/compute only)\n"); 3162 P(RINT " -J disable output (check/compute only)\n");
3142 P(RINT " -P repeat count (for profiling)\n"); 3163 P(RINT " -P repeat count (for profiling)\n");
3143 P(RINT " -T use alternate code table\n"); 3164 P(RINT " -T use alternate code table\n");
3144 P(RINT " -n disable checksum (encode/decode)\n");
3145#endif 3165#endif
3146 return EXIT_FAILURE; 3166 return EXIT_FAILURE;
3147} 3167}
diff --git a/xdelta3/xdelta3-regtest.py b/xdelta3/xdelta3-regtest.py
index 7bb7a1c..bf064bb 100755
--- a/xdelta3/xdelta3-regtest.py
+++ b/xdelta3/xdelta3-regtest.py
@@ -611,15 +611,15 @@ def BigFileRun(f1, f2):
611def RandomBigRun(f1, f2): 611def RandomBigRun(f1, f2):
612 612
613 input_ranges = [ 613 input_ranges = [
614 (7, 9, 'large_look'), 614 (7, 20, 'large_look'),
615 (1, 10, 'large_step'), 615 (1, 30, 'large_step'),
616 (4, 5, 'small_look'), 616 (4, 5, 'small_look'),
617 (1, 20, 'small_chain'), 617 (1, 32, 'small_chain'),
618 (1, 10, 'small_lchain'), 618 (1, 16, 'small_lchain'),
619 (0, 1, 'ssmatch'), 619 (0, 1, 'ssmatch'),
620 (0, 1, 'trylazy'), 620 (0, 1, 'trylazy'),
621 (1, 32, 'max_lazy'), 621 (1, 128, 'max_lazy'),
622 (1, 64, 'long_enough'), 622 (1, 256, 'long_enough'),
623 (0, 1, 'promote'), 623 (0, 1, 'promote'),
624 ] 624 ]
625 625
diff --git a/xdelta3/xdelta3-test.h b/xdelta3/xdelta3-test.h
index 2c7af22..36166c6 100755
--- a/xdelta3/xdelta3-test.h
+++ b/xdelta3/xdelta3-test.h
@@ -2049,9 +2049,9 @@ test_string_matching (xd3_stream *stream, int ignore)
2049 if ((ret = stream->smatcher.string_match (stream))) { return ret; } 2049 if ((ret = stream->smatcher.string_match (stream))) { return ret; }
2050 2050
2051 *rptr = 0; 2051 *rptr = 0;
2052 while (! xd3_rlist_empty (& stream->iopt.used)) 2052 while (! xd3_rlist_empty (& stream->iopt_used))
2053 { 2053 {
2054 xd3_rinst *inst = xd3_rlist_pop_front (& stream->iopt.used); 2054 xd3_rinst *inst = xd3_rlist_pop_front (& stream->iopt_used);
2055 2055
2056 switch (inst->type) 2056 switch (inst->type)
2057 { 2057 {
@@ -2072,7 +2072,7 @@ test_string_matching (xd3_stream *stream, int ignore)
2072 2072
2073 *rptr++ = ' '; 2073 *rptr++ = ' ';
2074 2074
2075 xd3_rlist_push_back (& stream->iopt.free, inst); 2075 xd3_rlist_push_back (& stream->iopt_free, inst);
2076 } 2076 }
2077 2077
2078 if (rptr != rbuf) 2078 if (rptr != rbuf)
diff --git a/xdelta3/xdelta3.c b/xdelta3/xdelta3.c
index 14a3c08..97c3390 100755
--- a/xdelta3/xdelta3.c
+++ b/xdelta3/xdelta3.c
@@ -550,7 +550,7 @@ static void* xd3_alloc0 (xd3_stream *stream,
550static xd3_output* xd3_alloc_output (xd3_stream *stream, 550static xd3_output* xd3_alloc_output (xd3_stream *stream,
551 xd3_output *old_output); 551 xd3_output *old_output);
552 552
553 553static int xd3_alloc_iopt (xd3_stream *stream, int elts);
554 554
555static void xd3_free_output (xd3_stream *stream, 555static void xd3_free_output (xd3_stream *stream,
556 xd3_output *output); 556 xd3_output *output);
@@ -2281,11 +2281,20 @@ xd3_free_output (xd3_stream *stream,
2281void 2281void
2282xd3_free_stream (xd3_stream *stream) 2282xd3_free_stream (xd3_stream *stream)
2283{ 2283{
2284 xd3_iopt_buflist *blist = stream->iopt_alloc;
2285
2286 do
2287 {
2288 xd3_iopt_buflist *tmp = blist;
2289 blist = blist->next;
2290 xd3_free (stream, tmp->buffer);
2291 xd3_free (stream, tmp);
2292 }
2293 while (blist != NULL);
2284 2294
2285 xd3_free (stream, stream->large_table); 2295 xd3_free (stream, stream->large_table);
2286 xd3_free (stream, stream->small_table); 2296 xd3_free (stream, stream->small_table);
2287 xd3_free (stream, stream->small_prev); 2297 xd3_free (stream, stream->small_prev);
2288 xd3_free (stream, stream->iopt.buffer);
2289 2298
2290#if XD3_ENCODER 2299#if XD3_ENCODER
2291 { 2300 {
@@ -2393,6 +2402,12 @@ xd3_config_stream(xd3_stream *stream,
2393 stream->srcwin_size = config->srcwin_size ? config->srcwin_size : XD3_DEFAULT_CKSUM_ADVANCE; 2402 stream->srcwin_size = config->srcwin_size ? config->srcwin_size : XD3_DEFAULT_CKSUM_ADVANCE;
2394 stream->srcwin_maxsz = config->srcwin_maxsz ? config->srcwin_maxsz : XD3_DEFAULT_SRCWINSZ; 2403 stream->srcwin_maxsz = config->srcwin_maxsz ? config->srcwin_maxsz : XD3_DEFAULT_SRCWINSZ;
2395 2404
2405 if (stream->iopt_size == 0)
2406 {
2407 stream->iopt_size = XD3_ALLOCSIZE / sizeof(xd3_rinst);
2408 stream->iopt_unlimited = 1;
2409 }
2410
2396 stream->getblk = config->getblk; 2411 stream->getblk = config->getblk;
2397 stream->alloc = config->alloc ? config->alloc : __xd3_alloc_func; 2412 stream->alloc = config->alloc ? config->alloc : __xd3_alloc_func;
2398 stream->free = config->freef ? config->freef : __xd3_free_func; 2413 stream->free = config->freef ? config->freef : __xd3_free_func;
@@ -2663,8 +2678,8 @@ xd3_set_appheader (xd3_stream *stream,
2663static int 2678static int
2664xd3_iopt_check (xd3_stream *stream) 2679xd3_iopt_check (xd3_stream *stream)
2665{ 2680{
2666 int ul = xd3_rlist_length (& stream->iopt.used); 2681 int ul = xd3_rlist_length (& stream->iopt_used);
2667 int fl = xd3_rlist_length (& stream->iopt.free); 2682 int fl = xd3_rlist_length (& stream->iopt_free);
2668 2683
2669 return (ul + fl + (stream->iout ? 1 : 0)) == stream->iopt_size; 2684 return (ul + fl + (stream->iout ? 1 : 0)) == stream->iopt_size;
2670} 2685}
@@ -2674,7 +2689,7 @@ static xd3_rinst*
2674xd3_iopt_free (xd3_stream *stream, xd3_rinst *i) 2689xd3_iopt_free (xd3_stream *stream, xd3_rinst *i)
2675{ 2690{
2676 xd3_rinst *n = xd3_rlist_remove (i); 2691 xd3_rinst *n = xd3_rlist_remove (i);
2677 xd3_rlist_push_back (& stream->iopt.free, i); 2692 xd3_rlist_push_back (& stream->iopt_free, i);
2678 return n; 2693 return n;
2679} 2694}
2680 2695
@@ -2683,7 +2698,7 @@ xd3_iopt_free_nonadd (xd3_stream *stream, xd3_rinst *i)
2683{ 2698{
2684 if (i->type != XD3_ADD) 2699 if (i->type != XD3_ADD)
2685 { 2700 {
2686 xd3_rlist_push_back (& stream->iopt.free, i); 2701 xd3_rlist_push_back (& stream->iopt_free, i);
2687 } 2702 }
2688} 2703}
2689 2704
@@ -2885,7 +2900,7 @@ xd3_iopt_add_finalize (xd3_stream *stream)
2885static int 2900static int
2886xd3_iopt_flush_instructions (xd3_stream *stream, int force) 2901xd3_iopt_flush_instructions (xd3_stream *stream, int force)
2887{ 2902{
2888 xd3_rinst *r1 = xd3_rlist_front (& stream->iopt.used); 2903 xd3_rinst *r1 = xd3_rlist_front (& stream->iopt_used);
2889 xd3_rinst *r2; 2904 xd3_rinst *r2;
2890 xd3_rinst *r3; 2905 xd3_rinst *r3;
2891 usize_t r1end; 2906 usize_t r1end;
@@ -2901,8 +2916,8 @@ xd3_iopt_flush_instructions (xd3_stream *stream, int force)
2901 /* Note: once tried to skip this step if it's possible to assert there are no 2916 /* Note: once tried to skip this step if it's possible to assert there are no
2902 * overlapping instructions. Doesn't work because xd3_opt_erase leaves overlapping 2917 * overlapping instructions. Doesn't work because xd3_opt_erase leaves overlapping
2903 * instructions. */ 2918 * instructions. */
2904 while (! xd3_rlist_end (& stream->iopt.used, r1) && 2919 while (! xd3_rlist_end (& stream->iopt_used, r1) &&
2905 ! xd3_rlist_end (& stream->iopt.used, r2 = xd3_rlist_next (r1))) 2920 ! xd3_rlist_end (& stream->iopt_used, r2 = xd3_rlist_next (r1)))
2906 { 2921 {
2907 r1end = r1->pos + r1->size; 2922 r1end = r1->pos + r1->size;
2908 2923
@@ -2919,7 +2934,7 @@ xd3_iopt_flush_instructions (xd3_stream *stream, int force)
2919 XD3_ASSERT (r2end > (r1end + LEAST_MATCH_INCR)); 2934 XD3_ASSERT (r2end > (r1end + LEAST_MATCH_INCR));
2920 2935
2921 /* If r3 is available... */ 2936 /* If r3 is available... */
2922 if (! xd3_rlist_end (& stream->iopt.used, r3 = xd3_rlist_next (r2))) 2937 if (! xd3_rlist_end (& stream->iopt_used, r3 = xd3_rlist_next (r2)))
2923 { 2938 {
2924 /* If r3 starts before r1 finishes or just about, r2 is irrelevant */ 2939 /* If r3 starts before r1 finishes or just about, r2 is irrelevant */
2925 if (r3->pos <= r1end + 1) 2940 if (r3->pos <= r1end + 1)
@@ -3026,9 +3041,9 @@ xd3_iopt_flush_instructions (xd3_stream *stream, int force)
3026 3041
3027 /* If forcing, pick instructions until the list is empty, otherwise this empties 50% of 3042 /* If forcing, pick instructions until the list is empty, otherwise this empties 50% of
3028 * the queue. */ 3043 * the queue. */
3029 for (flushed = 0; ! xd3_rlist_empty (& stream->iopt.used); ) 3044 for (flushed = 0; ! xd3_rlist_empty (& stream->iopt_used); )
3030 { 3045 {
3031 xd3_rinst *renc = xd3_rlist_pop_front (& stream->iopt.used); 3046 xd3_rinst *renc = xd3_rlist_pop_front (& stream->iopt_used);
3032 if ((ret = xd3_iopt_add_encoding (stream, renc))) 3047 if ((ret = xd3_iopt_add_encoding (stream, renc)))
3033 { 3048 {
3034 return ret; 3049 return ret;
@@ -3044,10 +3059,10 @@ xd3_iopt_flush_instructions (xd3_stream *stream, int force)
3044 /* If there are only two instructions remaining, break, because they were 3059 /* If there are only two instructions remaining, break, because they were
3045 * not optimized. This means there were more than 50% eliminated by the 3060 * not optimized. This means there were more than 50% eliminated by the
3046 * loop above. */ 3061 * loop above. */
3047 r1 = xd3_rlist_front (& stream->iopt.used); 3062 r1 = xd3_rlist_front (& stream->iopt_used);
3048 if (xd3_rlist_end(& stream->iopt.used, r1) || 3063 if (xd3_rlist_end(& stream->iopt_used, r1) ||
3049 xd3_rlist_end(& stream->iopt.used, r2 = xd3_rlist_next (r1)) || 3064 xd3_rlist_end(& stream->iopt_used, r2 = xd3_rlist_next (r1)) ||
3050 xd3_rlist_end(& stream->iopt.used, r3 = xd3_rlist_next (r2))) 3065 xd3_rlist_end(& stream->iopt_used, r3 = xd3_rlist_next (r2)))
3051 { 3066 {
3052 break; 3067 break;
3053 } 3068 }
@@ -3056,7 +3071,7 @@ xd3_iopt_flush_instructions (xd3_stream *stream, int force)
3056 3071
3057 XD3_ASSERT (xd3_iopt_check (stream)); 3072 XD3_ASSERT (xd3_iopt_check (stream));
3058 3073
3059 XD3_ASSERT (!force || xd3_rlist_length (& stream->iopt.used) == 0); 3074 XD3_ASSERT (!force || xd3_rlist_length (& stream->iopt_used) == 0);
3060 3075
3061 return 0; 3076 return 0;
3062} 3077}
@@ -3067,19 +3082,33 @@ xd3_iopt_get_slot (xd3_stream *stream, xd3_rinst** iptr)
3067 xd3_rinst *i; 3082 xd3_rinst *i;
3068 int ret; 3083 int ret;
3069 3084
3070 if (xd3_rlist_empty (& stream->iopt.free)) 3085 if (xd3_rlist_empty (& stream->iopt_free))
3071 { 3086 {
3072 if ((ret = xd3_iopt_flush_instructions (stream, 0))) { return ret; } 3087 if (stream->iopt_unlimited)
3088 {
3089 int elts = XD3_ALLOCSIZE / sizeof(xd3_rinst);
3090 if ((ret = xd3_alloc_iopt (stream, elts)))
3091 {
3092 return ret;
3093 }
3094 stream->iopt_size += elts;
3095 }
3096 else
3097 {
3098 if ((ret = xd3_iopt_flush_instructions (stream, 0))) { return ret; }
3073 3099
3074 XD3_ASSERT (! xd3_rlist_empty (& stream->iopt.free)); 3100 XD3_ASSERT (! xd3_rlist_empty (& stream->iopt_free));
3101 }
3075 } 3102 }
3076 3103
3077 i = xd3_rlist_pop_back (& stream->iopt.free); 3104 i = xd3_rlist_pop_back (& stream->iopt_free);
3078 3105
3079 xd3_rlist_push_back (& stream->iopt.used, i); 3106 xd3_rlist_push_back (& stream->iopt_used, i);
3080 3107
3081 (*iptr) = i; 3108 (*iptr) = i;
3082 3109
3110 ++stream->i_slots_used;
3111
3083 return 0; 3112 return 0;
3084} 3113}
3085 3114
@@ -3090,9 +3119,9 @@ xd3_iopt_get_slot (xd3_stream *stream, xd3_rinst** iptr)
3090static void 3119static void
3091xd3_iopt_erase (xd3_stream *stream, usize_t pos, usize_t size) 3120xd3_iopt_erase (xd3_stream *stream, usize_t pos, usize_t size)
3092{ 3121{
3093 while (! xd3_rlist_empty (& stream->iopt.used)) 3122 while (! xd3_rlist_empty (& stream->iopt_used))
3094 { 3123 {
3095 xd3_rinst *r = xd3_rlist_back (& stream->iopt.used); 3124 xd3_rinst *r = xd3_rlist_back (& stream->iopt_used);
3096 3125
3097 /* Verify that greedy is working. The previous instruction should end before the 3126 /* Verify that greedy is working. The previous instruction should end before the
3098 * new one begins. */ 3127 * new one begins. */
@@ -3110,7 +3139,8 @@ xd3_iopt_erase (xd3_stream *stream, usize_t pos, usize_t size)
3110 3139
3111 /* Otherwise, the new instruction covers the old one, delete it and repeat. */ 3140 /* Otherwise, the new instruction covers the old one, delete it and repeat. */
3112 xd3_rlist_remove (r); 3141 xd3_rlist_remove (r);
3113 xd3_rlist_push_back (& stream->iopt.free, r); 3142 xd3_rlist_push_back (& stream->iopt_free, r);
3143 --stream->i_slots_used;
3114 } 3144 }
3115} 3145}
3116 3146
@@ -3120,12 +3150,12 @@ xd3_iopt_last_matched (xd3_stream *stream)
3120{ 3150{
3121 xd3_rinst *r; 3151 xd3_rinst *r;
3122 3152
3123 if (xd3_rlist_empty (& stream->iopt.used)) 3153 if (xd3_rlist_empty (& stream->iopt_used))
3124 { 3154 {
3125 return 0; 3155 return 0;
3126 } 3156 }
3127 3157
3128 r = xd3_rlist_back (& stream->iopt.used); 3158 r = xd3_rlist_back (& stream->iopt_used);
3129 3159
3130 return r->pos + r->size; 3160 return r->pos + r->size;
3131} 3161}
@@ -3430,6 +3460,31 @@ xd3_encode_buffer_leftover (xd3_stream *stream)
3430 return 0; 3460 return 0;
3431} 3461}
3432 3462
3463/* Allocates one block of xd3_rlist elements */
3464static int
3465xd3_alloc_iopt (xd3_stream *stream, int elts)
3466{
3467 int i;
3468 xd3_iopt_buflist* next = stream->iopt_alloc;
3469 xd3_iopt_buflist* last = xd3_alloc (stream, sizeof (xd3_iopt_buflist), 1);
3470
3471 if (last == NULL ||
3472 (last->buffer = xd3_alloc (stream, sizeof (xd3_rinst), elts)) == NULL)
3473 {
3474 return ENOMEM;
3475 }
3476
3477 last->next = next;
3478 stream->iopt_alloc = last;
3479
3480 for (i = 0; i < elts; i += 1)
3481 {
3482 xd3_rlist_push_back (& stream->iopt_free, & last->buffer[i]);
3483 }
3484
3485 return 0;
3486}
3487
3433/* This function allocates all memory initially used by the encoder. */ 3488/* This function allocates all memory initially used by the encoder. */
3434static int 3489static int
3435xd3_encode_init (xd3_stream *stream) 3490xd3_encode_init (xd3_stream *stream)
@@ -3454,9 +3509,9 @@ xd3_encode_init (xd3_stream *stream)
3454 3509
3455 if (small_comp) 3510 if (small_comp)
3456 { 3511 {
3457 /* Hard-coded, keeps table small because small matches become inefficient. */ 3512 /* Hard-coded, keeps table small because small matches become inefficient.
3458 // TODO: verify this 3513 * TODO: verify this stuff. */
3459 usize_t hash_values = min(stream->winsize, 65536U); 3514 usize_t hash_values = min(stream->winsize, XD3_DEFAULT_SPREVSZ);
3460 3515
3461 xd3_size_hashtable (stream, 3516 xd3_size_hashtable (stream,
3462 hash_values, 3517 hash_values,
@@ -3474,21 +3529,13 @@ xd3_encode_init (xd3_stream *stream)
3474 } 3529 }
3475 3530
3476 /* iopt buffer */ 3531 /* iopt buffer */
3477 xd3_rlist_init (& stream->iopt.used); 3532 xd3_rlist_init (& stream->iopt_used);
3478 xd3_rlist_init (& stream->iopt.free); 3533 xd3_rlist_init (& stream->iopt_free);
3479 3534
3480 if ((stream->iopt.buffer = xd3_alloc (stream, sizeof (xd3_rinst), stream->iopt_size)) == NULL) 3535 if (xd3_alloc_iopt (stream, stream->iopt_size) != 0) { goto fail; }
3481 {
3482 goto fail;
3483 }
3484
3485 for (i = 0; i < stream->iopt_size; i += 1)
3486 {
3487 xd3_rlist_push_back (& stream->iopt.free, & stream->iopt.buffer[i]);
3488 }
3489 3536
3490 XD3_ASSERT (xd3_rlist_length (& stream->iopt.free) == stream->iopt_size); 3537 XD3_ASSERT (xd3_rlist_length (& stream->iopt_free) == stream->iopt_size);
3491 XD3_ASSERT (xd3_rlist_length (& stream->iopt.used) == 0); 3538 XD3_ASSERT (xd3_rlist_length (& stream->iopt_used) == 0);
3492 3539
3493 /* address cache, code table */ 3540 /* address cache, code table */
3494 stream->acache.s_near = stream->code_table_desc->near_modes; 3541 stream->acache.s_near = stream->code_table_desc->near_modes;
@@ -3532,6 +3579,7 @@ xd3_encode_reset (xd3_stream *stream)
3532 IF_DEBUG (stream->n_emit = 0); 3579 IF_DEBUG (stream->n_emit = 0);
3533 stream->avail_in = 0; 3580 stream->avail_in = 0;
3534 stream->small_reset = 1; 3581 stream->small_reset = 1;
3582 stream->i_slots_used = 0;
3535 3583
3536 if (stream->src != NULL) 3584 if (stream->src != NULL)
3537 { 3585 {
diff --git a/xdelta3/xdelta3.h b/xdelta3/xdelta3.h
index a9ca8f1..c2fe0a6 100755
--- a/xdelta3/xdelta3.h
+++ b/xdelta3/xdelta3.h
@@ -74,7 +74,8 @@
74 74
75/* The IOPT_SIZE value sets the size of a buffer used to batch overlapping copy 75/* The IOPT_SIZE value sets the size of a buffer used to batch overlapping copy
76 * instructions before they are optimized by picking the best non-overlapping ranges. The 76 * instructions before they are optimized by picking the best non-overlapping ranges. The
77 * larger this buffer, the longer a forced xd3_srcwin_setup() decision is held off. */ 77 * larger this buffer, the longer a forced xd3_srcwin_setup() decision is held off.
78 * Setting this value to 0 causes an unlimited buffer to be used. */
78#ifndef XD3_DEFAULT_IOPT_SIZE 79#ifndef XD3_DEFAULT_IOPT_SIZE
79#define XD3_DEFAULT_IOPT_SIZE (1U<<12) 80#define XD3_DEFAULT_IOPT_SIZE (1U<<12)
80#endif 81#endif
@@ -192,7 +193,7 @@ typedef struct _xd3_rpage xd3_rpage;
192typedef struct _xd3_addr_cache xd3_addr_cache; 193typedef struct _xd3_addr_cache xd3_addr_cache;
193typedef struct _xd3_output xd3_output; 194typedef struct _xd3_output xd3_output;
194typedef struct _xd3_desect xd3_desect; 195typedef struct _xd3_desect xd3_desect;
195typedef struct _xd3_iopt_buf xd3_iopt_buf; 196typedef struct _xd3_iopt_buflist xd3_iopt_buflist;
196typedef struct _xd3_rlist xd3_rlist; 197typedef struct _xd3_rlist xd3_rlist;
197typedef struct _xd3_sec_type xd3_sec_type; 198typedef struct _xd3_sec_type xd3_sec_type;
198typedef struct _xd3_sec_cfg xd3_sec_cfg; 199typedef struct _xd3_sec_cfg xd3_sec_cfg;
@@ -484,13 +485,12 @@ struct _xd3_addr_cache
484 usize_t *same_array; /* array of size s_same*256 */ 485 usize_t *same_array; /* array of size s_same*256 */
485}; 486};
486 487
487/* the IOPT buffer has a used list of (ordered) instructions, possibly overlapping in 488/* the IOPT buffer list is just a list of buffers, which may be allocated
488 * target addresses, awaiting a flush */ 489 * during encode when using an unlimited buffer. */
489struct _xd3_iopt_buf 490struct _xd3_iopt_buflist
490{ 491{
491 xd3_rlist used;
492 xd3_rlist free;
493 xd3_rinst *buffer; 492 xd3_rinst *buffer;
493 xd3_iopt_buflist *next;
494}; 494};
495 495
496/* This is the record of a pre-compiled configuration, a subset of xd3_config. */ 496/* This is the record of a pre-compiled configuration, a subset of xd3_config. */
@@ -634,6 +634,7 @@ struct _xd3_stream
634 usize_t sprevsz; /* small string, previous window size (power of 2) */ 634 usize_t sprevsz; /* small string, previous window size (power of 2) */
635 usize_t sprevmask; /* small string, previous window size mask */ 635 usize_t sprevmask; /* small string, previous window size mask */
636 uint iopt_size; 636 uint iopt_size;
637 uint iopt_unlimited;
637 uint srcwin_size; 638 uint srcwin_size;
638 uint srcwin_maxsz; 639 uint srcwin_maxsz;
639 640
@@ -698,8 +699,10 @@ struct _xd3_stream
698 xd3_output *enc_heads[4]; /* array of encoded outputs: head of chain */ 699 xd3_output *enc_heads[4]; /* array of encoded outputs: head of chain */
699 xd3_output *enc_tails[4]; /* array of encoded outputs: tail of chain */ 700 xd3_output *enc_tails[4]; /* array of encoded outputs: tail of chain */
700 701
701 xd3_iopt_buf iopt; /* instruction optimizing buffer */ 702 xd3_rlist iopt_used; /* instruction optimizing buffer */
703 xd3_rlist iopt_free;
702 xd3_rinst *iout; /* next single instruction */ 704 xd3_rinst *iout; /* next single instruction */
705 xd3_iopt_buflist *iopt_alloc;
703 706
704 const uint8_t *enc_appheader; /* application header to encode */ 707 const uint8_t *enc_appheader; /* application header to encode */
705 usize_t enc_appheadsz; /* application header size */ 708 usize_t enc_appheadsz; /* application header size */
@@ -785,6 +788,8 @@ struct _xd3_stream
785 xoff_t l_add; 788 xoff_t l_add;
786 xoff_t l_run; 789 xoff_t l_run;
787 790
791 usize_t i_slots_used;
792
788#if XD3_DEBUG 793#if XD3_DEBUG
789 usize_t sh_searches; 794 usize_t sh_searches;
790 usize_t sh_compares; 795 usize_t sh_compares;