| 1 | import os |
| 2 | import time |
| 3 | |
| 4 | const compare_prod = '-prod' in os.args |
| 5 | |
| 6 | const cleanup_tmp = '-no-cleanup' !in os.args |
| 7 | |
| 8 | const fetch_remote = '-no-fetch' !in os.args |
| 9 | |
| 10 | fn gbranch() string { |
| 11 | return os.execute(r'git branch --list|grep ^\*').output.trim_left('* ').trim_space() |
| 12 | } |
| 13 | |
| 14 | fn gcommit() string { |
| 15 | return os.execute(r'git rev-parse --short=7 HEAD').output.trim_left('* ').trim_space() |
| 16 | } |
| 17 | |
| 18 | fn r(cmd string) { |
| 19 | res := os.system(cmd) |
| 20 | if res != 0 { |
| 21 | eprintln('> failed running: `${cmd}`') |
| 22 | exit(1) |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | fn xtime(cmd string) { |
| 27 | $if linux { |
| 28 | r('/usr/bin/time -f "CPU: %Us\tReal: %es\tElapsed: %E\tRAM: %MKB\t%C" ${cmd}') |
| 29 | return |
| 30 | } |
| 31 | $if macos { |
| 32 | r('/opt/homebrew/bin/gtime -f "CPU: %Us\tReal: %es\tElapsed: %E\tRAM: %MKB\t%C" ${cmd}') |
| 33 | return |
| 34 | } |
| 35 | // Pure V fallback - no memory stats, but better than nothing ... |
| 36 | before := time.now() |
| 37 | r(cmd) |
| 38 | after := time.now() |
| 39 | delta_time := after - before |
| 40 | println('> Elapsed time: ${delta_time.milliseconds()} ms, for cmd: ${cmd}') |
| 41 | } |
| 42 | |
| 43 | fn show_size(fpath string) { |
| 44 | println('>Size of ${fpath:20s}: ${os.file_size(fpath):10}') |
| 45 | } |
| 46 | |
| 47 | fn compare_size(fpath1 string, fpath2 string) { |
| 48 | size1 := os.file_size(fpath1) |
| 49 | size2 := os.file_size(fpath2) |
| 50 | diff_ := i64(size2) - i64(size1) |
| 51 | println('>>>>>> size("${fpath2:17}") - size("${fpath1:17}") = ${size2:10} - ${size1:10} = ${diff_:10}') |
| 52 | } |
| 53 | |
| 54 | fn vcompare(vold string, vnew string) { |
| 55 | r("v repeat --nmaxs 7 -R 3 '${vold} -check-syntax examples/hello_world.v' '${vnew} -check-syntax examples/hello_world.v'") |
| 56 | r("v repeat --nmaxs 7 -R 3 '${vold} -check examples/hello_world.v' '${vnew} -check examples/hello_world.v'") |
| 57 | r("v repeat --nmaxs 7 -R 3 '${vold} -no-parallel -o ohw.c examples/hello_world.v' '${vnew} -no-parallel -o nhw.c examples/hello_world.v'") |
| 58 | compare_size('ohw.c', 'nhw.c') |
| 59 | r("v repeat --nmaxs 7 -R 3 '${vold} -no-parallel -o ohw.exe examples/hello_world.v' '${vnew} -no-parallel -o nhw.exe examples/hello_world.v'") |
| 60 | compare_size('ohw.exe', 'nhw.exe') |
| 61 | |
| 62 | r("v repeat --nmaxs 7 -R 3 '${vold} -check-syntax cmd/v' '${vnew} -check-syntax cmd/v'") |
| 63 | r("v repeat --nmaxs 7 -R 3 '${vold} -check cmd/v' '${vnew} -check cmd/v'") |
| 64 | r("v repeat --nmaxs 7 -R 3 '${vold} -no-parallel -o ov.c cmd/v' '${vnew} -no-parallel -o nv.c cmd/v'") |
| 65 | compare_size('ov.c', 'nv.c') |
| 66 | r("v repeat --nmaxs 7 -R 3 '${vold} -no-parallel -o ov.exe cmd/v' '${vnew} -no-parallel -o nv.exe cmd/v'") |
| 67 | compare_size('ov.exe', 'nv.exe') |
| 68 | } |
| 69 | |
| 70 | fn hline(header_message string) { |
| 71 | println('='.repeat(98)) |
| 72 | println(header_message) |
| 73 | } |
| 74 | |
| 75 | fn main() { |
| 76 | // The starting point, when this program should be started, is just after `gh pr checkout NUMBER`. |
| 77 | start := time.now() |
| 78 | pr_branch := gbranch() |
| 79 | pr_commit := gcommit() |
| 80 | hline('Current git branch: ${pr_branch}, commit: ${pr_commit}') |
| 81 | println(' Compiling new V executables from PR branch: ${pr_branch}, commit: ${pr_commit} ...') |
| 82 | // *not* using v self here is deliberate, so that the `v` executable itself, is not changed after running this script |
| 83 | xtime('./v -o vnew1 cmd/v') |
| 84 | xtime('./vnew1 -o vnew2 cmd/v') |
| 85 | xtime('./vnew2 -no-parallel -o vnew cmd/v') |
| 86 | xtime('./vnew -no-parallel -o nhw_current.c examples/hello_world.v') |
| 87 | xtime('./vnew -no-parallel -o nhw_current_gcc.c -cc gcc examples/hello_world.v') |
| 88 | xtime('./vnew -no-parallel -o nv_current.c cmd/v') |
| 89 | if compare_prod { |
| 90 | xtime('./vnew -no-parallel -prod -o vnew_prod cmd/v') |
| 91 | } |
| 92 | show_size('nhw_current.c') |
| 93 | show_size('nhw_current_gcc.c') |
| 94 | show_size('nv_current.c') |
| 95 | show_size('vnew') |
| 96 | if compare_prod { |
| 97 | show_size('vnew_prod') |
| 98 | } |
| 99 | r('rm -rf vnew1 vnew2') |
| 100 | |
| 101 | if fetch_remote { |
| 102 | // make sure to always compare against the main V repo's master branch by default: |
| 103 | os.execute('git -C . remote add V_REPO https://github.com/vlang/v.git') |
| 104 | os.execute('git -C . fetch V_REPO') |
| 105 | os.execute('git branch -D v_repo_master') |
| 106 | os.execute('git branch -f --track v_repo_master V_REPO/master') |
| 107 | } |
| 108 | |
| 109 | r('git checkout v_repo_master') |
| 110 | master_branch := gbranch() |
| 111 | hline(' Compiling old V executables from branch: ${master_branch}, commit: ${gcommit()} ...') |
| 112 | // Use `make` to bootstrap the old V from the C sources on the master branch, |
| 113 | // because the new V compiler may have breaking changes that prevent it from |
| 114 | // compiling the old code directly. |
| 115 | xtime('make -j4') |
| 116 | xtime('./v -o vold1 cmd/v') |
| 117 | xtime('./vold1 -no-parallel -o vold cmd/v') |
| 118 | xtime('./vold -no-parallel -o ohw_master.c examples/hello_world.v') |
| 119 | xtime('./vold -no-parallel -o ohw_master_gcc.c -cc gcc examples/hello_world.v') |
| 120 | xtime('./vold -no-parallel -o ov_master.c cmd/v') |
| 121 | if compare_prod { |
| 122 | xtime('./vold -no-parallel -prod -o vold_prod cmd/v') |
| 123 | show_size('vold_prod') |
| 124 | } |
| 125 | show_size('ohw_master.c') |
| 126 | show_size('ohw_master_gcc.c') |
| 127 | show_size('ov_master.c') |
| 128 | show_size('vold') |
| 129 | if compare_prod { |
| 130 | show_size('vold_prod') |
| 131 | } |
| 132 | r('rm -rf vold1') |
| 133 | |
| 134 | hline('File sizes so far ...') |
| 135 | compare_size('ohw_master.c', 'nhw_current.c') |
| 136 | compare_size('ohw_master_gcc.c', 'nhw_current_gcc.c') |
| 137 | compare_size('ov_master.c', 'nv_current.c') |
| 138 | compare_size('vold', 'vnew') |
| 139 | |
| 140 | r('git checkout ${pr_branch}') |
| 141 | // we are on the PR branch again |
| 142 | hline(' Measuring at PR branch: ${pr_branch}, commit: ${gcommit()} ...') |
| 143 | if compare_prod { |
| 144 | vcompare('./vold_prod', './vnew_prod') |
| 145 | } else { |
| 146 | vcompare('./vold', './vnew') |
| 147 | } |
| 148 | println('Done. Total time: ${(time.now() - start).seconds()} s.') |
| 149 | |
| 150 | hline('Final summary for file diff sizes on their own branches:') |
| 151 | compare_size('ohw_master.c', 'nhw_current.c') |
| 152 | compare_size('ohw_master_gcc.c', 'nhw_current_gcc.c') |
| 153 | compare_size('ov_master.c', 'nv_current.c') |
| 154 | compare_size('vold', 'vnew') |
| 155 | if compare_prod { |
| 156 | compare_size('vold_prod', 'vnew_prod') |
| 157 | } |
| 158 | |
| 159 | hline('Final summary for file diff sizes for generated files on the *current* branch:') |
| 160 | compare_size('ohw.c', 'nhw.c') |
| 161 | compare_size('ov.c', 'nv.c') |
| 162 | compare_size('ohw.exe', 'nhw.exe') |
| 163 | compare_size('ov.exe', 'nv.exe') |
| 164 | |
| 165 | // After all the measurements are done, delete all the generated temporary files, |
| 166 | // except the `vold` and `vnew` compilers, so that they can be used later in manual |
| 167 | // experiments: |
| 168 | if cleanup_tmp { |
| 169 | r('rm -rf ohw* nhw* nv* ov*') |
| 170 | } |
| 171 | } |
| 172 | |