diff --git a/development/keystest/autolyx b/development/keystest/autolyx index 228fd12b12..bf9f48ad1f 100755 --- a/development/keystest/autolyx +++ b/development/keystest/autolyx @@ -10,33 +10,67 @@ OUTDIR="$DIRNAME0/out" ROOT_OUTDIR="$DIRNAME0/out" THIS_PID=$$ +EXE_TO_TEST=src/lyx +if [ ! -e "$EXE_TO_TEST" ] +then + echo "$EXE_TO_TEST" does not exist + echo Cannot proceed + exit +fi + +#BORED_AFTER_SECS=7200 #If we have spend more than 3600 secs (an hour) replaying a file, without learning anything new, go and start looking for more bugs instead BORED_AFTER_SECS=3600 #If we have spend more than 3600 secs (an hour) replaying a file, without learning anything new, go and start looking for more bugs instead +LAST_CORE="" + ############################# # This section of code is LyX Specific ############################# -if [ ! -e lib/doc.orig ] +if [ ! -e $DIRNAME0/.lyx ] then - mv lib/doc lib/doc.orig + echo WARNING $DIRNAME0/.lyx does not exist + echo will need to regenerate .lyx every test fi +#if [ ! -e lib/doc.orig ] +#then +# mv lib/doc lib/doc.orig +#fi + +kill_all_children() { + kill `list_all_children.sh $1` + sleep 0.1 + kill -9 `list_all_children.sh $1` +} + + + ensure_cannot_print () { -lpq && ( +if [ ! -z "$REPLAYFILE" ] +then + return +fi +if lpq +then + echo We can print, this is bad! echo use lpadmin to stop keytest from destroying a forest. full_exit sleep 999999 ; read -) +else + echo "Phew, lpq reckons we aren't ready to print. This is a *good* thing!" +fi } extras_save () { + return for f in `ls lib/doc` do if [ lib/doc/$f -nt lib/doc.orig/$f -o ! -e lib/doc.orig/$f ] then - echo making doc dir $OUTDIR/$SEC.doc + #echo making doc dir $OUTDIR/$SEC.doc mkdir -p $OUTDIR/$SEC.doc cp -a lib/doc/$f $OUTDIR/$SEC.doc/ fi @@ -44,6 +78,7 @@ extras_save () { } extras_prepare () { + return mkdir -p lib/doc/ rm lib/doc/*.lyx cp -p lib/doc.orig/*.lyx lib/doc/ @@ -59,31 +94,71 @@ calc_confirm_file() { echo "$ROOT_OUTDIR/$id.reproduced" } +get_pid () { + sleep 3 + echo getting pidof "$1" 1>&2 + #PID=`ps "-u$USER" "$2" | grep "$1" | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` + PID=`ps x | grep "$1" | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` + echo "$PID" | ( grep " " > /dev/null && ( echo too many PIDs 1>&2 ; full_exit ) ) + nPIDs=`echo PID "$PID" | wc -l` + echo nPIDs $nPIDs 1>&2 + sleep 1 + echo -- if [ "$nPIDs" != "1" ] 1>&2 + if test "$nPIDs" != "1" #2> /tmp/testerr + then + echo autolyx: Wrong number of PIDs "$nPIDs" "($1)" "($2)" 1>&2 + fi + echo "$PID" + echo got pidof "$1" 1>&2 +} +clean_up () { + KT_PID=`get_pid keytest.py x` + kill $KT_PID + sleep 0.1 + kill -9 $KT_PID +} + full_exit() { + clean_up + echo attempting to exit this entire script... normal exit may just exit one function kill $THIS_PID sleep 1 echo We should not get this far sleep 1 - kill -9 $THIS_PIS - echo We really should not get this far + kill -9 $THIS_PID + echo We really should not get this far exit } +run_gdb () { + echo Starting GDB + (echo " + shell svn info src/ + run + bt + shell kill $CHILD_PID + shell wmctrl -l + shell sleep 1 + shell kill -9 $CHILD_PID +" ; yes q) | HOME="$NEWHOME" gdb src/lyx 2>&1 | strings| tee $GDB + echo "end run_gdb" + #### gcore $GDB.core + #shell wmctrl -r __renamed__ -b add,shaded + #shell wmctrl -r term -b add,shaded + #shell wmctrl -r term -b add,shaded + #shell wmctrl -R lyx' + # + #shell import -window root '$GDB.png' + #shell import -window root '$GDB..png' + #exit +} + + ########################### -get_pid () { - echo getting pidof "$1" 1>&2 - PID=`ps a"$2" | grep "$1" | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` - echo "$PID" | ( grep " " > /dev/null && ( echo too many PIDs 1>&2 ; full_exit ) ) - nPIDs=`echo PID "$PID" | wc -l` - if [ "$nPIDs" != "1" ] - then - echo autolyx: Wrong number of PIDs "$nPIDs" 1>&2 - fi - echo "$PID" -} + try_replay () { id=`get_crash_id` @@ -113,20 +188,192 @@ do_replay() { wait "$TEST_PID" } +test_replayed () { + test -e "$f.replay/last_crash_sec" -o -e "$f.replay/Irreproducible" +} + +move_to_replayed () { + mkdir -p $REPLAY_DIR/replayed + mv $f* $REPLAY_DIR/replayed +} + do_queued_replays() { -for f in `ls development/keytest/out/toreplay/*KEYCODEpure` +REPLAY_DIR=development/keytest/out/toreplay +for f in `ls $REPLAY_DIR/*KEYCODEpure` do - if [ ! -e "$f.replay/last_crash_sec" ] + if test_replayed then + move_to_replayed + else #./development/keytest/killtest killall lyx sleep 1 killall -9 lyx KEYCODEpure="$f" do_replay + #if test_replayed + #then + move_to_replayed + #fi fi + done } +#get_pid() { +# ps a | grep $1 | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//' +#} + +do_one_test() { + GDB=$OUTDIR/$SEC.GDB + KEYCODE=$OUTDIR/$SEC.KEYCODE + KEYCODEpure=$OUTDIR/$SEC.KEYCODEpure + NEWHOME=~/kt.dir/$SEC.dir + mkdir -p $NEWHOME + NEWHOME=`cd $NEWHOME; pwd` + echo NEWHOME $NEWHOME + mkdir -p "$NEWHOME" + cp -rv $DIRNAME0/.lyx "$NEWHOME"/ + killall -9 lyx latex pdflatex + ( sleep 9 && + ps a | grep lyx + echo -- 1 || full_exit + LYX_PID="" + i=0 + echo -- while [ -z "$LYX_PID" -a 200 -gt $i ] + while [ -z "$LYX_PID" -a 200 -gt $i ] + do + #export LYX_PID=`ps a | grep /src/lyx | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` + export LYX_PID=`get_pid "/src/lyx$" ` + echo LYXPID "$LYX_PID" || full_exit + sleep 0.1 + i=$(($i+1)) + done + echo `ps a | grep /src/lyx` + echo -- 2 + echo `ps a | grep /src/lyx | grep -v grep` + echo -- 3 + echo `ps a | grep /src/lyx | grep -v grep | sed 's/ [a-z].*$//'` + echo -- 4 + echo LYX_PID=$LYX_PID + echo XA_PRIMARY | xclip -selection XA_PRIMARY + echo XA_SECONDARY | xclip -selection XA_SECONDARY + echo XA_CLIPBOARD | xclip -selection XA_CLIPBOARD + + echo -- if [ ! -z "$LYX_PID" ] + if [ ! -z "$LYX_PID" ] + then + kill `ps a | grep keytest.py | grep -v grep | cut -c 1-5` + sleep 0.2 + kill -9 `ps a | grep keytest.py | grep -v grep | cut -c 1-5` + while ! wmctrl -r lyx -b add,maximized_vert,maximized_horz + do + echo trying to maximize lyx + sleep 1 + done + KEYTEST_OUTFILE="$KEYCODEpure" nice -19 python $DIRNAME0/keytest.py | tee $KEYCODE + #echo "$!" > $NEWHOME/keytest_py.pid + fi + killall lyx) & + CHILD_PID="$!" + ls src/lyx ; sleep 1 + pwd + + #You may want to use the following to simulate SIGFPE + #(sleep 90 && killall -8 lyx) & + echo TTL $TAIL_LINES + extras_prepare + ensure_cannot_print + run_gdb +# (run_gdb) & +# GDBTASK_PID="$!" +# (sleep 600 ; kill "$!") +# echo WAITING FOR: wait $GDBTASK_PID +# wait $GDBTASK_PID +# echo NOLONGER waiting for: wait $GDBTASK_PID + + echo END gdb + kill $CHILD_PID + KT_PID=`get_pid keytest.py` + echo KT_PID=$KT_PID + kill $KT_PID + sleep 0.3 + kill -9 $CHILD_PID + kill -9 $KT_PID + # Or use "exited normally": + echo END gdb2 + # these tend to take up a huge amount of space: + rm -rf $NEWHOME + if (grep " signal SIG[^TK]" $GDB || grep KILL_FREEZE $KEYCODE) + then + extras_save + mkdir -p $OUTDIR/save && ( + ln $OUTDIR/$SEC.* $OUTDIR/save || + cp $OUTDIR/$SEC.* $OUTDIR/save) + LAST_CRASH_SEC=$SEC + echo $LAST_CRASH_SEC > $OUTDIR/last_crash_sec + if [ ! -z "$TAIL_LINES" ] + then + LAST_EVENT="$SEC" + echo Reproducible > $OUTDIR/Reproducible + fi + TAIL_LINES="" + if [ -z "$REPLAYFILE" ] + then + echo ATTEMPTING TO REPLAY + try_replay + else + export KEYTEST_INFILE=$KEYCODEpure + NUM_KEYCODES=`wc -l < $KEYCODEpure` + echo NUM_KEYCODES $NUM_KEYCODES, was $LAST_NUM_KEYCODES + if [ "$NUM_KEYCODES" != "$LAST_NUM_KEYCODES" ] + then + LAST_EVENT="$SEC" + LAST_NUM_KEYCODES=$NUM_KEYCODES + echo "Hooray! we have eleminated some keycodes" + fi + fi + if [ ! -z "$AND_THEN_QUIT" ] + then + RESULT=1 + echo RR 1 + return 1 + fi + if [ ! -z "$LAST_CORE" ] + then + rm "$LAST_CORE" + fi + LAST_CORE="$GDB.core" + else + rm -rf $BAK/* + mv $OUTDIR/$SEC.* $BAK/ + if [ ! -z "$TAIL_LINES" ] + then + echo TTL3 $TAIL_LINES + echo MAX_TAIL_LINES "$MAX_TAIL_LINES" + TAIL_LINES=$(($TAIL_LINES*2)) + echo TTL4 $TAIL_LINES + if [ "$TAIL_LINES" -ge "0$MAX_TAIL_LINES" -a ! -z "$MAX_TAIL_LINES" ] + then + echo Giving up because $TAIL_LINES '>' $MAX_TAIL_LINES + echo Irreproducible > $OUTDIR/Irreproducible + full_exit + fi + fi + if [ ! -z "$AND_THEN_QUIT" ] + then + RESULT=0 + echo RR 0 + return 0 + fi + + echo TTL2 $TAIL_LINES + fi +} + +if [ ! -z "$1" ] +then + REPLAYFILE=$1 +fi if [ ! -z "$REPLAYFILE" ] then @@ -151,17 +398,49 @@ echo X_PID $X_PID export TAIL_LINES=$TAIL_LINES echo TL $TAIL_LINES - + BAK="$OUTDIR/backup" mkdir -p $BAK + + + #rename other windows to avoid confusion. wmctrl -N __renamed__ -r lyx wmctrl -N __renamed__ -r lyx wmctrl -N __renamed__ -r lyx wmctrl -N __renamed__ -r lyx export PATH=`cd $DIRNAME0; pwd`/path:$PATH + +if [ ! -z "$1" ] +then + SEC=`date +%s` + export MAX_DROP=0 + if [ ".$SCREENSHOT_OUT." = ".auto." ] + then + echo SCREENSHOT_OUT was $SCREENSHOT_OUT. + export SCREENSHOT_OUT="$OUTDIR/$SEC.s" + echo SCREENSHOT_OUT is $SCREENSHOT_OUT. + #exit + fi + export RESULT=179 + do_one_test #| tee do_one_test.log + RESULT="$?" + echo Ressult $RESULT + + kill `list_all_children.sh $$` + sleep 0.1 + kill -9 `list_all_children.sh $$` + + exit $RESULT + + #echo done ; sleep 1 + full_exit +fi + + + ( echo TTL $TAIL_LINES @@ -199,129 +478,18 @@ do echo echo $LAST_CRASH_SEC > $OUTDIR/Finished mkdir $OUTDIR/final - ln $OUTDIR/$SEC* $OUTDIR/final + ln $OUTDIR/$SEC* $OUTDIR/final || cp $OUTDIR/$SEC* $OUTDIR/final CONFIRM_FILE=`calc_confirm_file` echo Reproducible > "$CONFIRM_FILE" full_exit fi + else + do_queued_replays fi - - GDB=$OUTDIR/$SEC.GDB - KEYCODE=$OUTDIR/$SEC.KEYCODE - KEYCODEpure=$OUTDIR/$SEC.KEYCODEpure - NEWHOME=~/kt.dir/$SEC.dir - mkdir -p $NEWHOME - NEWHOME=`cd $NEWHOME; pwd` - echo NEWHOME $NEWHOME - mkdir -p "$NEWHOME" - cp -rv ~/.lyx "$NEWHOME"/ - killall -9 lyx - ( sleep 25 && - ps a | grep lyx - echo -- 1 - LYX_PID="" - i=0 - while [ -z "$LYX_PID" -a 200 -gt $i ] - do - export LYX_PID=`ps a | grep /src/lyx | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` - echo LYXPID "$LYX_PID" - sleep 0.1 - i=$(($i+1)) - done - echo `ps a | grep /src/lyx` - echo -- 2 - echo `ps a | grep /src/lyx | grep -v grep` - echo -- 3 - echo `ps a | grep /src/lyx | grep -v grep | sed 's/ [a-z].*$//'` - echo -- 4 - echo LYX_PID=$LYX_PID - echo XA_PRIMARY | xclip -selection XA_PRIMARY - echo XA_SECONDARY | xclip -selection XA_SECONDARY - echo XA_CLIPBOARD | xclip -selection XA_CLIPBOARD - - if [ ! -z "$LYX_PID" ] - then - kill `ps a | grep keytest.py | grep -v grep | cut -c 1-5` - sleep 0.2 - kill -9 `ps a | grep keytest.py | grep -v grep | cut -c 1-5` - KEYTEST_OUTFILE="$KEYCODEpure" nice -19 python $DIRNAME0/keytest.py | tee $KEYCODE - fi - killall lyx) & - CHILD_PID="$!" - ls src/lyx ; sleep 1 - pwd - - #You may want to use the following to simulate SIGFPE - #(sleep 90 && killall -8 lyx) & - echo TTL $TAIL_LINES - extras_prepare - ensure_cannot_print - echo Starting GDB - (echo " - shell svn info src/ - run - bt - shell kill $CHILD_PID - shell import -window root '$GDB.png' - shell wmctrl -l - shell sleep 1 - shell kill -9 $CHILD_PID - shell wmctrl -r __renamed__ -b add,shaded - shell wmctrl -r term -b add,shaded - shell wmctrl -r term -b add,shaded - shell wmctrl -R lyx - shell import -window root '$GDB..png' - " ; yes q) | HOME="$NEWHOME" gdb src/lyx 2>&1 | strings| tee $GDB - echo END gdb - kill $CHILD_PID - sleep 0.3 - kill -9 $CHILD_PID - # Or use "exited normally": - if grep " signal SIG[^T]" $GDB - then - extras_save - LAST_CRASH_SEC=$SEC - echo $LAST_CRASH_SEC > $OUTDIR/last_crash_sec - if [ ! -z "$TAIL_LINES" ] - then - LAST_EVENT="$SEC" - echo Reproducible > $OUTDIR/Reproducible - fi - TAIL_LINES="" - if [ -z "$REPLAYFILE" ] - then - echo ATTEMPTING TO REPLAY - try_replay - else - export KEYTEST_INFILE=$KEYCODEpure - NUM_KEYCODES=`wc -l < $KEYCODEpure` - echo NUM_KEYCODES $NUM_KEYCODES, was $LAST_NUM_KEYCODES - if [ "$NUM_KEYCODES" != "$LAST_NUM_KEYCODES" ] - then - LAST_EVENT="$SEC" - LAST_NUM_KEYCODES=$NUM_KEYCODES - echo "Hooray! we have eleminated some keycodes" - fi - fi - else - rm -r $BAK/* - mv $OUTDIR/$SEC.* $BAK/ - if [ ! -z "$TAIL_LINES" ] - then - echo TTL3 $TAIL_LINES - echo MAX_TAIL_LINES "$MAX_TAIL_LINES" - TAIL_LINES=$(($TAIL_LINES*2)) - echo TTL4 $TAIL_LINES - if [ "$TAIL_LINES" -ge "0$MAX_TAIL_LINES" -a ! -z "$MAX_TAIL_LINES" ] - then - echo Giving up because $TAIL_LINES '>' $MAX_TAIL_LINES - echo Irreproducible > $OUTDIR/Irreproducible - full_exit - fi - fi - echo TTL2 $TAIL_LINES - fi + do_one_test done +kill_all_children $$ ) 2>&1 |tee $OUTDIR/log +kill_all_children $$ diff --git a/development/keystest/cache-bisect.py b/development/keystest/cache-bisect.py new file mode 100755 index 0000000000..e379743579 --- /dev/null +++ b/development/keystest/cache-bisect.py @@ -0,0 +1,321 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import os +from subprocess import call, check_call +from random import randrange +import getpass + + +outfilename = "/tmp/cache-bisect." + getpass.getuser() + ".log" +outfile = open(outfilename, 'w') +print 'BBBISECT_BEGIN' +#print >> outfile, 'BBBISECT_BEGIN' +#print >> outfile, 'BBBISECT_BEGIN' +#print >> outfile, 'BBBISECT_BEGIN' +#print >> outfile, 'BBBISECT_BEGIN' +#print >> outfile, 'BBBISECT_BEGIN' +#print 'BBBISECT_BEGIN' + +source_dir = '/mnt/big/xp/src/lyx-1.6.x-bisect' # must NOT end in a slash +cache_dir = source_dir + '.cache/' # must end in a slash +source_dir = '/mnt/big/xp/src/lyx-1.6.x-bisect2' # must NOT end in a slash + +#make_cmd = 'autoconf && ./configure && cd src && echo __________ `pwd` && sleep 9 && make' +make_cmd = 'rm -rf autom4te.cache && autoconf && ./configure && cd src && make' + +reverse_search = True +reverse_search = False +must_make = True # If we fail to make the file, we could this a "bad" rather than "canot test" +must_make = False + +# ToDo: +# replace .tmp with .partial_copy and .not_yet_made + + +def set_revision(new_v, tmp_d): + #check_call(['svn', 'up', '-r' + new_v, '--force'], cwd=tmp_d) + os.system ('cd "'+tmp_d+'" && yes tf | svn up -r'+new_v+'--force') + +def cmp_version(x, y): + return cmp(int(x), int(y)) + + +def get_cached_versions(): + vers = [f for f in os.listdir(cache_dir) if not f.count('.')] + vers.sort(cmp_version) + return vers + + +def version_in_range(v, lo, hi): + if cmp_version(v, lo) < 0: + return False + elif cmp_version(v, hi) > 0: + return False + return True + +def killall_p (s): + # Unlike killall, this searchs within command parameters, as well as the + # command name + + #os.system("kPID=`ps a | grep '"+s+"' | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'` + os.system("(kPID=`ps a | grep '"+s+ + "' | grep -v grep | sed 's/^ *//g'| sed 's/ .*$//'`\n\ + echo kPID $kPID "+s+"\n\ + echo kill $kPID\n\ + kill $kPID\n\ + sleep 0.1\n\ + echo kill -9 $kPID\n\ + kill -9 $kPID) 2> /dev/null") + +def clean_up (): + killall_p("autolyx") + killall_p("lyx") + killall_p("keytest.py") + killall_p("xclip") + +def filter_versions(vers, lo, hi): + return [v for v in vers if cmp] + + +def ver2dir(v): + return cache_dir + v + + +def make_ver(new_v, old_v=None, alt_v=None): + print 'MAKING', new_v, old_v, alt_v + new_d = ver2dir(new_v) + if old_v is None: + old_d = source_dir + else: + old_d = ver2dir(old_v) + fail_d = new_d + '.fail' + tmp_d = new_d + '.tmp' + if os.path.exists(cache_dir + fail_d): + return 1 + if os.path.exists(new_d): + return 0 + if not os.path.exists(tmp_d): + if not os.path.exists(old_d): + old_d = old_d + '.tmp' + call(['rm', '-rf', tmp_d + '.cp']) + call(['cp', '-rvu', old_d, tmp_d + '.cp']) + check_call(['mv', tmp_d + '.cp', tmp_d]) + set_revision(new_v, tmp_d) + call('pwd && sleep 5 && echo ' + make_cmd, cwd=tmp_d, shell=True) + result = call(make_cmd, cwd=tmp_d, shell=True) + if result == 0: + print 'Make successful' + check_call(['mv', tmp_d, new_d]) + return result + + +def change_after(cmd, v): + result = run_cmd(cmd, v) + ca = result_after(result) + print >> outfile, 'BISECT_change_after', v, ca + print 'BISECT_change_after', v, ca + return ca + + +def change_before(cmd, v): + result = run_cmd(cmd, v) + cb = result_before(result) + print >> outfile, 'BISECT_change_before', v, cb + print 'BISECT_change_before', v, cb + return cb + + +def result_after(i): + if reverse_search: + return result_bad(i) + else: + return result_good(i) + + +def result_before(i): + if reverse_search: + return result_good(i) + else: + return result_bad(i) + + +def result_good(i): + return i == 0 + + +def result_bad(i): + return not result_ugly(i) and not result_good(i) + + +def result_ugly(i): + return i == 125 # Like git, we treat 125 as "We cannot test this version" + + +def run_cmd(cmd, v): + #result = call('pwd ; echo SS ' + cmd, shell=True, cwd=ver2dir(v)) + print "CMD", cmd + print "V2D", ver2dir(v) + os + #result = subprocess.call(cmd, shell=True, cwd=ver2dir(v)) + result = call(cmd, cwd=ver2dir(v)) + clean_up() + print cmd, result + return result + + +def do_bisect(cmd, vers, build): + lo = 0 + hi = len(vers) - 1 + m = (lo + hi) / 2 + + print lo, hi, m + print vers[lo], vers[hi], vers[m] + print vers + + print >> outfile, 'VERS', final_vers + + while len(vers) > 2: + print 'i', lo, hi, m, cmd + print 'v', vers[lo], vers[hi], vers[m], cmd + print vers + + print '#ugly = Nonese' + + if build or must_make: + ugly = False + result = make_ver(vers[m], vers[lo], vers[hi]) + print 'AMKE RESULT', result + if not must_make: + if result > 0 and not must_make: + ugly = True # Not good, or bad, just ugly. + else: + result = run_cmd(cmd, vers[m]) + if not ugly: + if result > 127: + os._exit(1) + ugly = result_ugly(result) + if ugly: + print vers[m] + ' is UGLY' + del vers[m] + hi = len(vers) - 1 + m = randrange(0, len(vers)) + else: + if result_after(result): + print vers[m] + ' is AFTER' + del vers[lo:m] + else: + print vers[m] + ' is BEFORE' + del vers[m + 1:hi + 1] + hi = len(vers) - 1 + m = (lo + hi) / 2 + + print 'VERS REMAINING:', vers + + return vers + + +def check_bisect(cmd, vers): + lo = 0 + hi = len(vers) - 1 + l = vers[lo] + h = vers[hi] + if make_ver(l): + return False + if make_ver(h): + return False + if change_before(cmd, l): + print 'Cannot bisect, change before ' + l\ + + ' or regression test invalid' + return False + if change_after(cmd, h): + print 'Cannot bisect, change after ' + h\ + + ' or regression test invalid' + return False + return True + + +def do_check_bisect(cmd, vers, build): + print vers + if check_bisect(cmd, vers): + return do_bisect(cmd, vers, build) + else: + return + + +def open_and_readlines(fname): + f = open(fname, 'r') + lines = f.readlines() + for i in range(0, len(lines)): + lines[i] = lines[i].rstrip('\n') + return lines + + +def get_versions_between(l, h): + vers = [f for f in open_and_readlines('all_versions') + if version_in_range(f, l, h)] + vers.sort(cmp_version) + return vers + + +def get_cached_versions_between(l, h): + vers = [f for f in get_cached_versions() if version_in_range(f, l, h)] + vers.sort(cmp_version) + print 'BTWN', l, h, vers + return vers + + +def two_level_bisect(cmd, LO, HI): + if make_ver(LO): + return False + if make_ver(HI): + return False + vers = get_cached_versions_between(LO, HI) + print 'CACHED_VERSIONS', vers + vers = do_check_bisect(cmd, vers, False) + print 'Closest Cached Versions', vers + if vers is None: + return + if len(vers) != 2: + return + vers = get_versions_between(vers[0], vers[1]) + print 'BETWEEN VERSIONS', vers + vers = do_check_bisect(cmd, vers, True) + + +def multisect(cmd, vers): + i = 1 + while i < len(vers): + print >> outfile, 'MULTISECT', vers[i] + print 'MULTISECT', vers[i] + if not ( make_ver(vers[i], vers[i-1])==0 and change_after(cmd, vers[i]) ) : + i = i + 1 + else: + return two_level_bisect(cmd, vers[i], vers[0]) + + +print 'BISECT_BEGIN' +print >> outfile, 'BISECT_BEGIN' +outfile.flush() +#final_vers = multisect('$TEST_COMMAND', ['30614', '27418', '23000']) +cmd = os.sys.argv +del cmd[0] + +VERS = os.environ.get('MULTISECT_VERS') +if VERS is None: + VERS = ['30614', '27418', '23000'] +else: + VERS = VERS.split() + +final_vers = multisect(cmd, VERS) +#final_vers = two_level_bisect('true', "21107","23000") +#final_vers = do_bisect('true', get_versions_between("21107","23000"),True) +outfile.flush() +print +print >> outfile, 'BISECT_FINAL', final_vers +print 'BISECT_FINAL', final_vers +os.system('echo BISECT_BEGIN >> /tmp/adsfadsf.log') +os.system('echo BISECT_FINAL >> /tmp/adsfadsf.log') + +clean_up() +os._exit(0) diff --git a/development/keystest/cache-bisect.sh b/development/keystest/cache-bisect.sh new file mode 100755 index 0000000000..a929406f8a --- /dev/null +++ b/development/keystest/cache-bisect.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Cache-bisect is +# roughly based on git-bisect, but uses SVN and caches every build tree +# to maximize performance. The idea here is that if the first few tests +# happen very quickly, and give plausible results, you can have +# confidence that you can just leave it running. Without that confidence +# I'd be continually thinking "Is the bisect still working, maybe I +# should check" so the bisect would be taking up my mental space. With +# cache-bisect, I can fire-and-forget, leaving the CPU to do the menial +# tasks while I think about other things. Additionally caching the +# build-trees cuts down on the amount of bandwidth required on the SVN +# server +# It uses three levels +# 1) At the bottom level, it bisects much like git-bisect +# 2) At the second level, it bisects, but only over cached revisions. +# 3) The the top level it does what I refer to as a "multisect". The +# idea is that you may not know which revision was a good revision, and +# picking revision 1 as the "good" revision is not only mildly wasteful +# but is likely to produce misleading results. Instead it starts +# stepping backwards, first trying 1.6.0, and then going backwards +# through trunk. + + KT=$(cd $(dirname "$0") && pwd) +$KT/cache-bisect.py "$@" | tee out/cache-bisect-$USER.log + + diff --git a/development/keystest/doNtimes.sh b/development/keystest/doNtimes.sh new file mode 100755 index 0000000000..0ea176d7cb --- /dev/null +++ b/development/keystest/doNtimes.sh @@ -0,0 +1,20 @@ +#!/bin/bash +KT=`dirname $0` +N=$1 +shift + +echo doNtimes .$N. "$@" + +i=0 +for intr in `yes | head -n$N` +do + i=$(($i+1)) + echo 'TRY#' $i + if ! "$@" + then + echo TRIES_REQUIRED: $i + exit 1 + fi +done + +echo DONE $N TIMES diff --git a/development/keystest/keytest.py b/development/keystest/keytest.py index aacbb4732b..4bbe3ce218 100755 --- a/development/keystest/keytest.py +++ b/development/keystest/keytest.py @@ -1,178 +1,266 @@ -#!/usr/bin/env python -#This script generated hundreds of random keypresses per second, +#!/usr/bin/python +# -*- coding: utf-8 -*- +# This script generates hundreds of random keypresses per second, # and sends them to the lyx window -#It requires xvkbd and wmctrl -#It generates a log of the KEYCODES it sends as development/keystest/out/KEYCODES +# It requires xvkbd and wmctrl +# It generates a log of the KEYCODES it sends as development/keystest/out/KEYCODES import random -import os +import os import re import sys +import time +#from subprocess import call +import subprocess -print "Beginning keytest.py" +print 'Beginning keytest.py' +DELAY = '59' class CommandSource: - def __init__(self): - keycode=["\[Left]",'\[Right]','\[Down]','\[Up]','\[BackSpace]','\[Delete]','\[Escape]'] - keycode[:0]=keycode - keycode[:0]=keycode - keycode[:0]=['\\'] + def __init__(self): + keycode = [ + "\[Left]", + '\[Right]', + '\[Down]', + '\[Up]', + '\[BackSpace]', + '\[Delete]', + '\[Escape]', + ] + keycode[:0] = keycode + keycode[:0] = keycode - for k in range(97, 123): - keycode[:0]=chr(k) + keycode[:0] = ['\\'] - for k in range(97, 123): - keycode[:0]=["\A"+chr(k)] + for k in range(97, 123): + keycode[:0] = chr(k) - for k in range(97, 123): - keycode[:0]=["\A"+chr(k)] + for k in range(97, 123): + keycode[:0] = ["\A" + chr(k)] - for k in range(97, 123): - keycode[:0]=["\C"+chr(k)] + for k in range(97, 123): + keycode[:0] = ["\A" + chr(k)] - self.keycode=keycode; - self.count=0; - self.count_max=1999; + for k in range(97, 123): + keycode[:0] = ["\C" + chr(k)] + + self.keycode = keycode + self.count = 0 + self.count_max = 1999 + + def getCommand(self): + self.count = self.count + 1 + if self.count % 200 == 0: + return 'RaiseLyx' + elif self.count > self.count_max: + os._exit(0) + else: + keystr = '' + for k in range(1, 2): + keystr = keystr + self.keycode[random.randint(1, + len(self.keycode)) - 1] + return 'KK: ' + keystr - def getCommand(self): - self.count=self.count+1; - #if self.count > self.count_max: - if self.count%200==0: - #self.count=0 - return ("RaiseLyx") - elif self.count > self.count_max: - os._exit(0) - else: - keystr="" - for k in range(1,2): - keystr=keystr+self.keycode[random.randint(1,len(self.keycode))-1] - return "KK: "+keystr class CommandSourceFromFile(CommandSource): - def __init__(self,filename,p): - self.infile=open(filename,'r') - self.lines=self.infile.readlines() - self.p=p - self.i=0 - self.count=0 - self.loops=0 - #Now we start randomly dropping lines, which we hope are redundant - #p is the probability that any given line will be removed - if (p>0): - #The next couple of lines are to ensure that at least one line is dropped - drop=random.randint(0,len(self.lines)-1) - del self.lines[drop] - p=p-(1/len(self.lines)) - j=0 - origlines=self.lines - self.lines=[]; - for l in origlines: - if random.uniform(0,1) < self.p: - print "Randomly dropping line "+l+"\n" - else: - self.lines.append(l) - print "LINES\n" - print self.lines - sys.stdout.flush() - os.system("sleep 2") - - def getCommand(self): - if self.i >= len(self.lines): - if self.count >= 100 or self.loops>1: - os.system("sleep 1") - os._exit(0) - else: - self.loops=self.loops+1 - self.i=0 - return("Loop") - line=self.lines[self.i] - print "Line read: <<"+line+">>\n" - self.count=self.count+1 - self.i=self.i+1 - return(line.rstrip()) -def sendKeystring(keystr,LYX_PID): - print "sending keystring "+keystr+"\n" - if not re.match(".*\w.*", keystr): - print ("print ."+keystr+".\n") - keystr="a" - os.system("while ( test -e /proc/$LYX_PID/status && ! grep 'tate.*[(]sleeping[)]' /proc/$LYX_PID/status); do echo -n . ; sleep 0.02; done") - cmd="xvkbd -xsendevent -text '"+keystr+"';sleep 0.03" - sys.stdout.flush() - os.system(cmd) - sys.stdout.flush() + def __init__(self, filename, p): + + self.infile = open(filename, 'r') + self.lines = self.infile.readlines() + self.infile.close() + linesbak = self.lines + self.p = p + print p, self.p, 'self.p' + self.i = 0 + self.count = 0 + self.loops = 0 + + # Now we start randomly dropping lines, which we hope are redundant + # p is the probability that any given line will be removed + + if p > 0.001: + if random.uniform(0, 1) < 0.5: + print 'randomdrop_independant\n' + self.randomdrop_independant() + else: + print 'randomdrop_slice\n' + self.randomdrop_slice() + if screenshot_out is None: + count_atleast = 100 + else: + count_atleast = 1 + self.max_count = max(len(self.lines) + 20, count_atleast) + if len(self.lines) < 1: + self.lines = linesbak + + def randomdrop_independant(self): + p = self.p + + # The next couple of lines are to ensure that at least one line is dropped + + drop = random.randint(0, len(self.lines) - 1) + del self.lines[drop] + p = p - 1 / len(self.lines) + origlines = self.lines + self.lines = [] + for l in origlines: + if random.uniform(0, 1) < self.p: + print 'Randomly dropping line ' + l + '\n' + else: + self.lines.append(l) + print 'LINES\n' + print self.lines + sys.stdout.flush() + + def randomdrop_slice(self): + lines = self.lines + if random.uniform(0, 1) < 0.4: + lines.append(lines[0]) + del lines[0] + num_lines = len(lines) + max_drop = max(5, num_lines / 5) + num_drop = random.randint(1, 5) + drop_mid = random.randint(0, num_lines) + drop_start = max(drop_mid - num_drop / 2, 0) + drop_end = min(drop_start + num_drop, num_lines) + print drop_start, drop_mid, drop_end + print lines + del lines[drop_start:drop_end] + print lines + self.lines = lines + + def getCommand(self): + if self.count >= self.max_count: + os._exit(0) + if self.i >= len(self.lines): + self.loops = self.loops + 1 + self.i = 0 + return 'Loop' + line = self.lines[self.i] + self.count = self.count + 1 + self.i = self.i + 1 + print 'Line read: <<' + line + '>>\n' + return line.rstrip('\n').rstrip() + + +def lyx_sleeping(): + fname = '/proc/' + lyx_pid + '/status' + if not os.path.exists(fname): + return False + f = open(fname, 'r') + lines = f.readlines() + sleeping = lines[1].find('(sleeping)') > 0 + + # print 'LYX_STATE', lines[1] , 'SLEEPING=', sleeping + + return sleeping + + +def sendKeystring(keystr, LYX_PID): + + # print "sending keystring "+keystr+"\n" + + if not re.match(".*\w.*", keystr): + print 'print .' + keystr + '.\n' + keystr = 'a' + before_secs = time.time() + while not lyx_sleeping(): + time.sleep(0.02) + print '.', + if time.time() - before_secs > 180: + print 'Killing due to freeze (KILL_FREEZE)' + + # Do profiling, but sysprof has no command line interface? + # os.system("killall -KILL lyx") + + os._exit(1) + if not screenshot_out is None: + while not lyx_sleeping(): + time.sleep(0.02) + print '.', + print 'Making Screenshot: ' + screenshot_out + time.sleep(0.2) + os.system('import -window root '+screenshot_out+str(x.count)+".png") + time.sleep(0.1) + sys.stdout.flush() + subprocess.call(["xvkbd", "-xsendevent", "-delay", DELAY, "-text", keystr]) def RaiseWindow(): - os.system("echo x-session-manager PID: $X_PID.") - os.system("echo x-session-manager open files: `lsof -p $X_PID | grep ICE-unix | wc -l`") - os.system("wmctrl -l | ( grep '"+lyx_window_name+"' || ( killall lyx ; sleep 1 ; killall -9 lyx ))") - os.system("wmctrl -R '"+lyx_window_name+"' ;sleep 0.1") - - -lyx_pid=os.environ.get("LYX_PID") -print("lyx_pid: "+lyx_pid+"\n"); -infilename=os.environ.get("KEYTEST_INFILE") -outfilename=os.environ.get("KEYTEST_OUTFILE") -max_drop=os.environ.get("MAX_DROP") -lyx_window_name=os.environ.get("LYX_WINDOW_NAME"); + os.system("echo x-session-manager PID: $X_PID.") + os.system("echo x-session-manager open files: `lsof -p $X_PID | grep ICE-unix | wc -l`") + os.system("wmctrl -l | ( grep '"+lyx_window_name+"' || ( killall lyx ; sleep 1 ; killall -9 lyx ))") + os.system("wmctrl -R '"+lyx_window_name+"' ;sleep 0.1") -file_new_command=os.environ.get("FILE_NEW_COMMAND"); + +lyx_pid = os.environ.get('LYX_PID') +print 'lyx_pid: ' + lyx_pid + '\n' +infilename = os.environ.get('KEYTEST_INFILE') +outfilename = os.environ.get('KEYTEST_OUTFILE') +max_drop = os.environ.get('MAX_DROP') +lyx_window_name = os.environ.get('LYX_WINDOW_NAME') +screenshot_out = os.environ.get('SCREENSHOT_OUT') + +file_new_command = os.environ.get('FILE_NEW_COMMAND') if file_new_command is None: - file_new_command="\Afn" + file_new_command = "\Afn" -ResetCommand=os.environ.get("RESET_COMMAND"); +ResetCommand = os.environ.get('RESET_COMMAND') if ResetCommand is None: - ResetCommand="\[Escape]\[Escape]\[Escape]\[Escape]"+file_new_command - #ResetCommand="\[Escape]\[Escape]\[Escape]\[Escape]\Cw\Cw\Cw\Cw\Cw\Afn" + ResetCommand = "\[Escape]\[Escape]\[Escape]\[Escape]" + file_new_command + #ResetCommand="\[Escape]\[Escape]\[Escape]\[Escape]\Cw\Cw\Cw\Cw\Cw\Afn" if lyx_window_name is None: - lyx_window_name="LyX"; + lyx_window_name = 'LyX' -print("outfilename: "+outfilename+"\n") -print("max_drop: "+max_drop+"\n") +print 'outfilename: ' + outfilename + '\n' +print 'max_drop: ' + max_drop + '\n' if infilename is None: - print("infilename is None\n") - x=CommandSource() - print ("Using x=CommandSource\n"); + print 'infilename is None\n' + x = CommandSource() + print 'Using x=CommandSource\n' else: - print("infilename: "+infilename+"\n") - probability_we_drop_a_command=random.uniform(0,float(max_drop)) - print ("probability_we_drop_a_command: ") - print '%s'%(probability_we_drop_a_command) - print "\n" - x=CommandSourceFromFile(infilename,probability_we_drop_a_command) - print ("Using x=CommandSourceFromFile\n"); + print 'infilename: ' + infilename + '\n' + probability_we_drop_a_command = random.uniform(0, float(max_drop)) + print 'probability_we_drop_a_command: ' + print '%s' % probability_we_drop_a_command + print '\n' + x = CommandSourceFromFile(infilename, probability_we_drop_a_command) + print 'Using x=CommandSourceFromFile\n' -outfile=open(outfilename,'w') +outfile = open(outfilename, 'w') RaiseWindow() -sendKeystring("\Afn",lyx_pid) -write_commands=True; +sendKeystring("\Afn", lyx_pid) +write_commands = True while True: - os.system("echo -n LOADAVG:; cat /proc/loadavg") - c=x.getCommand() - if (c=="Loop"): - outfile.close() - outfile=open(outfilename+'+','w') - print ("Now Looping") - outfile.writelines(c+'\n') - outfile.flush() - if c=="RaiseLyx": - print ("Raising Lyx"); - RaiseWindow() - elif c[0:4]=="KK: ": - if os.path.exists("/proc/"+lyx_pid+"/status"): - sendKeystring(c[4:],lyx_pid) - else: - os.system("killall lyx; sleep 2 ; killall -9 lyx") - print ("No path /proc/"+lyx_pid+"/status, exiting") - os._exit(1) - elif (c=="Loop"): - RaiseWindow() - sendKeystring(ResetCommand,lyx_pid) - else: - print ("Unrecognised Command '"+c+"'\n") + os.system('echo -n LOADAVG:; cat /proc/loadavg') + c = x.getCommand() + if c == 'Loop': + outfile.close() + outfile = open(outfilename + '+', 'w') + print 'Now Looping' + outfile.writelines(c + '\n') + outfile.flush() + if c == 'RaiseLyx': + print 'Raising Lyx' + RaiseWindow() + elif c[0:4] == 'KK: ': + if os.path.exists('/proc/' + lyx_pid + '/status'): + sendKeystring(c[4:], lyx_pid) + else: + os.system('killall lyx; sleep 2 ; killall -9 lyx') + print 'No path /proc/' + lyx_pid + '/status, exiting' + os._exit(1) + elif c[0:4] == 'KD: ': + DELAY = c[4:].rstrip('\n') + print 'Setting DELAY to ' + DELAY + '.' + elif c == 'Loop': + RaiseWindow() + sendKeystring(ResetCommand, lyx_pid) + else: + print "Unrecognised Command '" + c + "'\n" diff --git a/development/keystest/killtest.sh b/development/keystest/killtest.sh index 9390c9510b..5f5a186980 100755 --- a/development/keystest/killtest.sh +++ b/development/keystest/killtest.sh @@ -1,11 +1,15 @@ -AUTOLYX=`ps gaux | grep autolyx | grep -v grep | sed 's/[^ ]* //' | sed s/0.0.*//g` -TESTPY=`ps gaux | grep test.py | grep -v grep | sed 's/[^ ]* //' | sed s/0.0.*//g` +#!/bin/sh +KT=`dirname "$0"` +AUTOLYX=`ps gux "-u$USER" | grep autolyx | grep -v grep | sed 's/[^ ]* //' | sed s/0.0.*//g` +TESTPY=`ps gux "-u$USER" | grep test.py | grep -v grep | sed 's/[^ ]* //' | sed s/0.0.*//g` + killall autolyx killall test.py killall lyx killall gdb killall xterm killall replay.sh +killall xclip kill $AUTOLYX $TESTPY sleep 0.3 killall autolyx -9 @@ -14,4 +18,7 @@ killall lyx -9 killall gdb -9 killall xterm -9 killall replay.sh -9 +killall xclip -9 +$KT/killall_p reproduce +$KT/killall_p doNtimes kill $AUTOLYX $TESTPY -9 diff --git a/development/keystest/killtestpy.sh b/development/keystest/killtestpy.sh old mode 100644 new mode 100755 diff --git a/development/keystest/list_all_children.sh b/development/keystest/list_all_children.sh new file mode 100755 index 0000000000..11359aed64 --- /dev/null +++ b/development/keystest/list_all_children.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +listall () { +PID_LIST="$*" +while [ ! -z "$PID_LIST" ] +do + #PID_LIST=`ps -o pid= --ppid "$PID_LIST"| sed 's/^ *//g'` + PID_LIST=`ps -o pid= --ppid "$PID_LIST"` + PID_LIST=`echo $PID_LIST` + #PID_LIST=`ps -o pid= --ppid "$PID_LIST"` + echo $PID_LIST +done +} + +kill_all_children () { + kill `listall "$*"` + sleep 0.1 + kill -9 `listall "$*"` +} + +if [ "$1"="$kill" ] +then + shift + kill_all_children "$*" +else + listall "$*" +fi diff --git a/development/keystest/make_screenshot_html.py b/development/keystest/make_screenshot_html.py new file mode 100755 index 0000000000..aed255be78 --- /dev/null +++ b/development/keystest/make_screenshot_html.py @@ -0,0 +1,69 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import re +import os +import sys + +# sec="1250005988" +# dir='.' + +# if len(sys.argv) > 1: + +wdir = sys.argv[1] +sec = sys.argv[2] +base_filename = sec + '.s' +reGetNumber = re.compile(base_filename + '(\d*).png') + +largest_screenshot_number = -1 + +for f in os.listdir(wdir): + + # print f + + m = reGetNumber.match(f) + if m: + + # print f + # print m.groups(1)[0] + + n = int(m.groups(1)[0]) + largest_screenshot_number = max(largest_screenshot_number, n) + +# print largest_screenshot_number + +keycodes = ['', 'KK: \Afn'] +keycodes.extend(open(wdir + '/' + sec + '.KEYCODEpure')) +keycodes.extend(open(wdir + '/' + sec + '.KEYCODEpure+')) + + +def Highlight_Keycode_i(keycodes, i): + s = '' + for (j, k) in enumerate(keycodes): + + # print k + + if k[0:4] == 'KK: ': + k = k[4:] + if j == i: + s = s + '' + k + '' + else: + s = s + k + return s + + +print '' +print '