# HG changeset patch # User Pascal Bellard # Date 1243511829 -7200 # Node ID 63bb627de1fba33bc63e769c627d1774646852fd # Parent db989f95819d822db78004229c4fe5e3c4968ebe busybox: add replay, speedup unlzma diff -r db989f95819d -r 63bb627de1fb busybox/receipt --- a/busybox/receipt Thu May 28 11:47:11 2009 +0200 +++ b/busybox/receipt Thu May 28 13:57:09 2009 +0200 @@ -34,6 +34,8 @@ mkswap.u install.u basename.u +unlzma.u +replay.u EOT cp ../stuff/$PACKAGE-$VERSION.config .config make oldconfig diff -r db989f95819d -r 63bb627de1fb busybox/stuff/busybox-1.12.0-replay.u --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/busybox/stuff/busybox-1.12.0-replay.u Thu May 28 13:57:09 2009 +0200 @@ -0,0 +1,222 @@ +--- busybox-1.12.0/util-linux/script.c ++++ busybox-1.12.0/util-linux/script.c +@@ -36,6 +36,15 @@ + const char *shell; + char shell_opt[] = "-i"; + char *shell_arg = NULL; ++ enum { ++ OPT_a = (1 << 0), ++ OPT_c = (1 << 1), ++ OPT_f = (1 << 2), ++ OPT_q = (1 << 3), ++#if ENABLE_REPLAY ++ OPT_t = (1 << 4), ++#endif ++ }; + + #if ENABLE_GETOPT_LONG + static const char getopt_longopts[] ALIGN1 = +@@ -43,25 +52,28 @@ + "command\0" Required_argument "c" + "flush\0" No_argument "f" + "quiet\0" No_argument "q" ++# if ENABLE_REPLAY ++ "timing\0" No_argument "t" ++# endif + ; + + applet_long_options = getopt_longopts; + #endif + opt_complementary = "?1"; /* max one arg */ +- opt = getopt32(argv, "ac:fq", &shell_arg); ++ opt = getopt32(argv, "ac:fq" USE_REPLAY("t") , &shell_arg); + //argc -= optind; + argv += optind; + if (argv[0]) { + fname = argv[0]; + } + mode = O_CREAT|O_TRUNC|O_WRONLY; +- if (opt & 1) { ++ if (opt & OPT_a) { + mode = O_CREAT|O_APPEND|O_WRONLY; + } +- if (opt & 2) { ++ if (opt & OPT_c) { + shell_opt[1] = 'c'; + } +- if (!(opt & 8)) { /* not -q */ ++ if (!(opt & OPT_q)) { + printf("Script started, file is %s\n", fname); + } + shell = getenv("SHELL"); +@@ -97,6 +109,10 @@ + #define buf bb_common_bufsiz1 + struct pollfd pfd[2]; + int outfd, count, loop; ++#if ENABLE_REPLAY ++ struct timeval tv; ++ double oldtime=time(NULL), newtime; ++#endif + + outfd = xopen(fname, mode); + pfd[0].fd = pty; +@@ -118,15 +134,27 @@ + } + if (pfd[0].revents) { + errno = 0; ++#if ENABLE_REPLAY ++ if (opt & OPT_t) { ++ gettimeofday(&tv, NULL); ++ } ++#endif + count = safe_read(pty, buf, sizeof(buf)); + if (count <= 0 && errno != EAGAIN) { + /* err/eof from pty: exit */ + goto restore; + } + if (count > 0) { ++#if ENABLE_REPLAY ++ if (opt & OPT_t) { ++ newtime = tv.tv_sec + (double) tv.tv_usec / 1000000; ++ fprintf(stderr, "%f %i\n", newtime - oldtime, count); ++ oldtime = newtime; ++ } ++#endif + full_write(STDOUT_FILENO, buf, count); + full_write(outfd, buf, count); +- if (opt & 4) { /* -f */ ++ if (opt & OPT_f) { + fsync(outfd); + } + } +@@ -158,7 +186,7 @@ + restore: + if (attr_ok == 0) + tcsetattr(0, TCSAFLUSH, &tt); +- if (!(opt & 8)) /* not -q */ ++ if (!(opt & OPT_q)) + printf("Script done, file is %s\n", fname); + return EXIT_SUCCESS; + } + +--- busybox-1.12.0/util-linux/Config.in ++++ busybox-1.12.0/util-linux/Config.in +@@ -719,6 +719,13 @@ + help + This allows you to parse /proc/profile for basic profiling. + ++config REPLAY ++ bool "replay" ++ default n ++ help ++ This program replays a typescript, using timing information ++ given by script -t. ++ + config RTCWAKE + bool "rtcwake" + default n + +--- busybox-1.12.0/util-linux/Kbuild ++++ busybox-1.12.0/util-linux/Kbuild +@@ -28,6 +28,7 @@ + lib-$(CONFIG_RDATE) += rdate.o + lib-$(CONFIG_RDEV) += rdev.o + lib-$(CONFIG_READPROFILE) += readprofile.o ++lib-$(CONFIG_REPLAY) += replay.o + lib-$(CONFIG_RTCWAKE) += rtcwake.o + lib-$(CONFIG_SCRIPT) += script.o + lib-$(CONFIG_SETARCH) += setarch.o + +--- busybox-1.12.0/include/applets.h +USE_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm)) ++++ busybox-1.12.0/include/applets.h +@@ -294,6 +294,7 @@ + USE_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) + USE_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, reboot)) + USE_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) ++USE_REPLAY(APPLET(replay, _BB_DIR_BIN, _BB_SUID_NEVER)) + USE_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) + USE_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) + USE_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER, restorecon)) + +--- busybox-1.12.0/include/usage.h ++++ busybox-1.12.0/include/usage.h +@@ -3244,6 +3244,11 @@ + "\n -g Process group id(s)" \ + "\n -u Process user name(s) and/or id(s)" \ + ++#define replay_trivial_usage \ ++ "timingfile [typescript [divisor]]" ++#define replay_full_usage "\n\n" \ ++ "Play back typescripts, using timing information" ++ + #define reset_trivial_usage \ + "" + #define reset_full_usage "\n\n" \ +@@ -3426,13 +3431,20 @@ + + #define script_trivial_usage \ + "[-afq] [-c COMMAND] [OUTFILE]" +-#define script_full_usage "\n\n" \ ++#define script_full_usage_base "\n\n" \ + "Options:" \ + "\n -a Append output" \ + "\n -c Run COMMAND, not shell" \ + "\n -f Flush output after each write" \ + "\n -q Quiet" \ + ++#ifdef USE_REPLAY ++#define script_full_usage script_full_usage_base \ ++ "\n -t Send timing to stderr" ++#else ++#define script_full_usage script_full_usage_base ++#endif ++ + #define sed_trivial_usage \ + "[-efinr] pattern [files...]" + #define sed_full_usage "\n\n" \ + +--- busybox-1.12.0/util-linux/replay.c ++++ busybox-1.12.0/util-linux/replay.c +@@ -0,0 +1,41 @@ ++/* vi: set sw=4 ts=4: */ ++/* ++ * replay - play back typescripts, using timing information ++ * ++ * pascal.bellard@ads-lu.com ++ * ++ * Licensed under GPLv2 or later, see file License in this tarball for details. ++ * ++ */ ++ ++#include "libbb.h" ++ ++int replay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; ++int replay_main(int argc, char **argv) ++{ ++ const char *script = "typescript"; ++ double delay, factor = 1000000.0; ++ int fd; ++ long count; ++ FILE *tfp; ++ ++ switch (argc) { ++ case 4: factor /= atof(argv[3]); ++ case 3: script = argv[2]; ++ case 2: break; ++ default: ++ bb_show_usage(); ++ } ++ ++ tfp = xfopen_for_read(argv[1]); ++ fd = open(script, O_RDONLY); ++ while (fscanf(tfp, "%lf %ld\n", &delay, &count) == 2) { ++ usleep(delay * factor); ++ bb_copyfd_exact_size(fd, STDOUT_FILENO, count); ++ } ++#if ENABLE_FEATURE_CLEAN_UP ++ close(fd); ++ fclose(tfp); ++#endif ++ return EXIT_SUCCESS; ++} diff -r db989f95819d -r 63bb627de1fb busybox/stuff/busybox-1.12.0-unlzma.u --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/busybox/stuff/busybox-1.12.0-unlzma.u Thu May 28 13:57:09 2009 +0200 @@ -0,0 +1,302 @@ +--- busybox-1.12.0/archival/libunarchive/decompress_unlzma.c ++++ busybox-1.12.0/archival/libunarchive/decompress_unlzma.c +@@ -14,8 +14,10 @@ + + #if ENABLE_FEATURE_LZMA_FAST + # define speed_inline ALWAYS_INLINE ++# define size_inline + #else + # define speed_inline ++# define size_inline ALWAYS_INLINE + #endif + + +@@ -44,8 +46,8 @@ + #define RC_MODEL_TOTAL_BITS 11 + + +-/* Called twice: once at startup and once in rc_normalize() */ +-static void rc_read(rc_t *rc) ++/* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */ ++static size_inline void rc_read(rc_t *rc) + { + int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE); + if (buffer_size <= 0) +@@ -54,8 +56,17 @@ + rc->buffer_end = RC_BUFFER + buffer_size; + } + ++/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */ ++static void rc_do_normalize(rc_t *rc) ++{ ++ if (rc->ptr >= rc->buffer_end) ++ rc_read(rc); ++ rc->range <<= 8; ++ rc->code = (rc->code << 8) | *rc->ptr++; ++} ++ + /* Called once */ +-static rc_t* rc_init(int fd) /*, int buffer_size) */ ++static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ + { + int i; + rc_t *rc; +@@ -63,17 +74,18 @@ + rc = xmalloc(sizeof(*rc) + RC_BUFFER_SIZE); + + rc->fd = fd; +- /* rc->buffer_size = buffer_size; */ +- rc->buffer_end = RC_BUFFER + RC_BUFFER_SIZE; + rc->ptr = rc->buffer_end; + +- rc->code = 0; +- rc->range = 0xFFFFFFFF; + for (i = 0; i < 5; i++) { ++#if ENABLE_FEATURE_LZMA_FAST + if (rc->ptr >= rc->buffer_end) + rc_read(rc); + rc->code = (rc->code << 8) | *rc->ptr++; ++#else ++ rc_do_normalize(rc); ++#endif + } ++ rc->range = 0xFFFFFFFF; + return rc; + } + +@@ -83,14 +95,6 @@ + free(rc); + } + +-/* Called twice, but one callsite is in speed_inline'd rc_is_bit_0_helper() */ +-static void rc_do_normalize(rc_t *rc) +-{ +- if (rc->ptr >= rc->buffer_end) +- rc_read(rc); +- rc->range <<= 8; +- rc->code = (rc->code << 8) | *rc->ptr++; +-} + static ALWAYS_INLINE void rc_normalize(rc_t *rc) + { + if (rc->range < (1 << RC_TOP_BITS)) { +@@ -98,49 +102,30 @@ + } + } + +-/* rc_is_bit_0 is called 9 times */ +-/* Why rc_is_bit_0_helper exists? +- * Because we want to always expose (rc->code < rc->bound) to optimizer. +- * Thus rc_is_bit_0 is always inlined, and rc_is_bit_0_helper is inlined +- * only if we compile for speed. +- */ +-static speed_inline uint32_t rc_is_bit_0_helper(rc_t *rc, uint16_t *p) ++/* rc_is_bit_1 is called 9 times */ ++static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) + { + rc_normalize(rc); + rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS); +- return rc->bound; ++ if (rc->code < rc->bound) { ++ rc->range = rc->bound; ++ *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS; ++ return 0; ++ } ++ else { ++ rc->range -= rc->bound; ++ rc->code -= rc->bound; ++ *p -= *p >> RC_MOVE_BITS; ++ return 1; ++ } + } +-static ALWAYS_INLINE int rc_is_bit_0(rc_t *rc, uint16_t *p) +-{ +- uint32_t t = rc_is_bit_0_helper(rc, p); +- return rc->code < t; +-} + +-/* Called ~10 times, but very small, thus inlined */ +-static speed_inline void rc_update_bit_0(rc_t *rc, uint16_t *p) +-{ +- rc->range = rc->bound; +- *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS; +-} +-static speed_inline void rc_update_bit_1(rc_t *rc, uint16_t *p) +-{ +- rc->range -= rc->bound; +- rc->code -= rc->bound; +- *p -= *p >> RC_MOVE_BITS; +-} +- + /* Called 4 times in unlzma loop */ +-static int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) ++static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) + { +- if (rc_is_bit_0(rc, p)) { +- rc_update_bit_0(rc, p); +- *symbol *= 2; +- return 0; +- } else { +- rc_update_bit_1(rc, p); +- *symbol = *symbol * 2 + 1; +- return 1; +- } ++ int ret = rc_is_bit_1(rc, p); ++ *symbol = *symbol * 2 + ret; ++ return ret; + } + + /* Called once */ +@@ -266,13 +251,13 @@ + header.dst_size = SWAP_LE64(header.dst_size); + + if (header.dict_size == 0) +- header.dict_size = 1; ++ header.dict_size++; + + buffer = xmalloc(MIN(header.dst_size, header.dict_size)); + + num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)); + p = xmalloc(num_probs * sizeof(*p)); +- num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp)); ++ num_probs += LZMA_LITERAL - LZMA_BASE_SIZE; + for (i = 0; i < num_probs; i++) + p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1; + +@@ -282,9 +267,8 @@ + int pos_state = (buffer_pos + global_pos) & pos_state_mask; + + prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state; +- if (rc_is_bit_0(rc, prob)) { ++ if (!rc_is_bit_1(rc, prob)) { + mi = 1; +- rc_update_bit_0(rc, prob); + prob = (p + LZMA_LITERAL + + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc) + + (previous_byte >> (8 - lc)) +@@ -340,26 +324,21 @@ + int offset; + uint16_t *prob_len; + +- rc_update_bit_1(rc, prob); + prob = p + LZMA_IS_REP + state; +- if (rc_is_bit_0(rc, prob)) { +- rc_update_bit_0(rc, prob); ++ if (!rc_is_bit_1(rc, prob)) { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < LZMA_NUM_LIT_STATES ? 0 : 3; + prob = p + LZMA_LEN_CODER; + } else { +- rc_update_bit_1(rc, prob); +- prob = p + LZMA_IS_REP_G0 + state; +- if (rc_is_bit_0(rc, prob)) { +- rc_update_bit_0(rc, prob); ++ prob += LZMA_IS_REP_G0 - LZMA_IS_REP; ++ if (!rc_is_bit_1(rc, prob)) { + prob = (p + LZMA_IS_REP_0_LONG + + (state << LZMA_NUM_POS_BITS_MAX) + + pos_state + ); +- if (rc_is_bit_0(rc, prob)) { +- rc_update_bit_0(rc, prob); ++ if (!rc_is_bit_1(rc, prob)) { + + state = state < LZMA_NUM_LIT_STATES ? 9 : 11; + #if ENABLE_FEATURE_LZMA_FAST +@@ -372,25 +351,16 @@ + len = 1; + goto string; + #endif +- } else { +- rc_update_bit_1(rc, prob); + } + } else { + uint32_t distance; + +- rc_update_bit_1(rc, prob); +- prob = p + LZMA_IS_REP_G1 + state; +- if (rc_is_bit_0(rc, prob)) { +- rc_update_bit_0(rc, prob); +- distance = rep1; +- } else { +- rc_update_bit_1(rc, prob); +- prob = p + LZMA_IS_REP_G2 + state; +- if (rc_is_bit_0(rc, prob)) { +- rc_update_bit_0(rc, prob); +- distance = rep2; +- } else { +- rc_update_bit_1(rc, prob); ++ prob += LZMA_IS_REP_G1 - LZMA_IS_REP_G0; ++ distance = rep1; ++ if (rc_is_bit_1(rc, prob)) { ++ prob += LZMA_IS_REP_G2 - LZMA_IS_REP_G1; ++ distance = rep2; ++ if (rc_is_bit_1(rc, prob)) { + distance = rep3; + rep3 = rep2; + } +@@ -404,24 +374,20 @@ + } + + prob_len = prob + LZMA_LEN_CHOICE; +- if (rc_is_bit_0(rc, prob_len)) { +- rc_update_bit_0(rc, prob_len); +- prob_len = (prob + LZMA_LEN_LOW +- + (pos_state << LZMA_LEN_NUM_LOW_BITS)); ++ if (!rc_is_bit_1(rc, prob_len)) { ++ prob_len += LZMA_LEN_LOW - LZMA_LEN_CHOICE ++ + (pos_state << LZMA_LEN_NUM_LOW_BITS); + offset = 0; + num_bits = LZMA_LEN_NUM_LOW_BITS; + } else { +- rc_update_bit_1(rc, prob_len); +- prob_len = prob + LZMA_LEN_CHOICE_2; +- if (rc_is_bit_0(rc, prob_len)) { +- rc_update_bit_0(rc, prob_len); +- prob_len = (prob + LZMA_LEN_MID +- + (pos_state << LZMA_LEN_NUM_MID_BITS)); ++ prob_len += LZMA_LEN_CHOICE_2 - LZMA_LEN_CHOICE; ++ if (!rc_is_bit_1(rc, prob_len)) { ++ prob_len += LZMA_LEN_MID - LZMA_LEN_CHOICE_2 ++ + (pos_state << LZMA_LEN_NUM_MID_BITS); + offset = 1 << LZMA_LEN_NUM_LOW_BITS; + num_bits = LZMA_LEN_NUM_MID_BITS; + } else { +- rc_update_bit_1(rc, prob_len); +- prob_len = prob + LZMA_LEN_HIGH; ++ prob_len += LZMA_LEN_HIGH - LZMA_LEN_CHOICE_2; + offset = ((1 << LZMA_LEN_NUM_LOW_BITS) + + (1 << LZMA_LEN_NUM_MID_BITS)); + num_bits = LZMA_LEN_NUM_HIGH_BITS; +@@ -440,17 +406,18 @@ + << LZMA_NUM_POS_SLOT_BITS); + rc_bit_tree_decode(rc, prob, LZMA_NUM_POS_SLOT_BITS, + &pos_slot); ++ rep0 = pos_slot; + if (pos_slot >= LZMA_START_POS_MODEL_INDEX) { + num_bits = (pos_slot >> 1) - 1; + rep0 = 2 | (pos_slot & 1); ++ prob = p + LZMA_ALIGN; + if (pos_slot < LZMA_END_POS_MODEL_INDEX) { + rep0 <<= num_bits; +- prob = p + LZMA_SPEC_POS + rep0 - pos_slot - 1; ++ prob += LZMA_SPEC_POS - LZMA_ALIGN - 1 + rep0 - pos_slot ; + } else { + num_bits -= LZMA_NUM_ALIGN_BITS; + while (num_bits--) + rep0 = (rep0 << 1) | rc_direct_bit(rc); +- prob = p + LZMA_ALIGN; + rep0 <<= LZMA_NUM_ALIGN_BITS; + num_bits = LZMA_NUM_ALIGN_BITS; + } +@@ -461,8 +428,7 @@ + rep0 |= i; + i <<= 1; + } +- } else +- rep0 = pos_slot; ++ } + if (++rep0 == 0) + break; + } diff -r db989f95819d -r 63bb627de1fb busybox/stuff/busybox-1.12.0.config --- a/busybox/stuff/busybox-1.12.0.config Thu May 28 11:47:11 2009 +0200 +++ b/busybox/stuff/busybox-1.12.0.config Thu May 28 13:57:09 2009 +0200 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.12.0 -# Wed May 27 18:07:33 2009 +# Thu May 28 13:47:09 2009 # CONFIG_HAVE_DOT_CONFIG=y @@ -500,7 +500,7 @@ CONFIG_FEATURE_VOLUMEID_EXT=y CONFIG_FEATURE_VOLUMEID_REISERFS=y CONFIG_FEATURE_VOLUMEID_FAT=y -# CONFIG_FEATURE_VOLUMEID_HFS is not set +CONFIG_FEATURE_VOLUMEID_HFS=y # CONFIG_FEATURE_VOLUMEID_JFS is not set CONFIG_FEATURE_VOLUMEID_XFS=y CONFIG_FEATURE_VOLUMEID_NTFS=y @@ -526,6 +526,7 @@ CONFIG_RDATE=y # CONFIG_RDEV is not set CONFIG_READPROFILE=y +CONFIG_REPLAY=y # CONFIG_RTCWAKE is not set CONFIG_SCRIPT=y CONFIG_SETARCH=y