| 1 | // vtest build: !musl? && !sanitized_job? |
| 2 | import os |
| 3 | import time |
| 4 | |
| 5 | const vexe = os.getenv('VEXE') |
| 6 | |
| 7 | const vroot = os.dir(vexe) |
| 8 | |
| 9 | fn test_vexe_exists() { |
| 10 | assert vexe.len > 0 |
| 11 | assert os.is_file(vexe) |
| 12 | } |
| 13 | |
| 14 | fn test_v_profile_works_when_interrupted() { |
| 15 | println(@FN) |
| 16 | $if windows { |
| 17 | if os.getenv('VTEST_RUN_PROFILE_INTERRUPTION').int() == 0 { |
| 18 | eprintln('> skipping ${@FN} on windows for now, since reading the output blocks currently') |
| 19 | return |
| 20 | } |
| 21 | } |
| 22 | sfile := 'vlib/v/slow_tests/profile/profile_test_interrupted.v' |
| 23 | program_source := os.join_path(vroot, sfile) |
| 24 | pid := os.getpid() |
| 25 | program_exe := os.join_path(os.cache_dir(), 'profile_test_interrupted_pid_${pid}.exe') |
| 26 | program_profile := os.join_path(os.cache_dir(), 'profile_test_interrupted_pid_${pid}.profile') |
| 27 | os.rm(program_exe) or {} |
| 28 | os.rm(program_profile) or {} |
| 29 | os.chdir(vroot) or {} |
| 30 | compile_cmd := '${os.quoted_path(vexe)} -skip-unused -o ${os.quoted_path(program_exe)} -profile ${os.quoted_path(program_profile)} ${os.quoted_path(program_source)}' |
| 31 | eprintln('> compiling cmd: ${compile_cmd}') |
| 32 | compilation_result := os.execute(compile_cmd) |
| 33 | assert compilation_result.exit_code == 0, compilation_result.output |
| 34 | eprintln('> compiled ${program_exe}') |
| 35 | mut p := os.new_process(program_exe) |
| 36 | p.set_redirect_stdio() |
| 37 | p.run() |
| 38 | eprintln('> started ${program_exe} at: ${time.now().format_ss_micro()}') |
| 39 | mut lines := []string{} |
| 40 | for p.is_alive() && lines.len < 5 { |
| 41 | if data := p.pipe_read(.stdout) { |
| 42 | lines << data.trim_space().split_into_lines() |
| 43 | } |
| 44 | time.sleep(10 * time.millisecond) |
| 45 | } |
| 46 | dump(lines) |
| 47 | assert lines.len > 4, lines.str() |
| 48 | assert lines.contains('0003 iteration'), lines.str() |
| 49 | eprintln('> stopping ${program_exe} at: ${time.now().format_ss_micro()}...') |
| 50 | p.signal_term() |
| 51 | eprintln('> waiting ${program_exe}') |
| 52 | p.wait() |
| 53 | eprintln('> closing ${program_exe}') |
| 54 | p.close() |
| 55 | assert p.code == 130 |
| 56 | assert p.status == .closed |
| 57 | eprintln('> reading profile_content from ${program_profile} ...') |
| 58 | profile_content := os.read_file(program_profile)! |
| 59 | assert profile_content.contains('str_intp') |
| 60 | assert profile_content.contains('println') |
| 61 | assert profile_content.contains('time__sleep') |
| 62 | assert profile_content.contains('main__main') |
| 63 | // dump(profile_content) |
| 64 | eprintln('-'.repeat(120)) |
| 65 | } |
| 66 | |
| 67 | fn test_v_profile_works() { |
| 68 | println(@FN) |
| 69 | sfile := 'vlib/v/slow_tests/profile/profile_test_1.v' |
| 70 | validate_output(@FN, '', sfile, { |
| 71 | 'builtin__arguments': 1 |
| 72 | 'main__main': 1 |
| 73 | 'builtin__println': 1 |
| 74 | 'strconv__atoi': 1 |
| 75 | }) |
| 76 | } |
| 77 | |
| 78 | fn test_v_profile_on_off_api_works() { |
| 79 | println(@FN) |
| 80 | sfile := 'vlib/v/slow_tests/profile/profile_test_2.v' |
| 81 | res_lines := validate_output(@FN, '', sfile, { |
| 82 | 'builtin__builtin_init': 1 |
| 83 | 'main__main': 1 |
| 84 | 'main__abc': 1 |
| 85 | }) |
| 86 | // test that `-d no_profile_startup` *also* works: |
| 87 | res2_lines := validate_output(@FN, '-d no_profile_startup', sfile, { |
| 88 | 'builtin__builtin_init': -1 |
| 89 | 'main__main': 1 |
| 90 | 'main__abc': 1 |
| 91 | }) |
| 92 | assert res_lines.len > res2_lines.len |
| 93 | // dump(res2_lines) |
| 94 | } |
| 95 | |
| 96 | fn test_v_profile_fns_option_works() { |
| 97 | println(@FN) |
| 98 | sfile := 'vlib/v/slow_tests/profile/profile_test_3.v' |
| 99 | validate_output(@FN, '-profile-fns builtin__println', sfile, { |
| 100 | 'main__main': -1 |
| 101 | 'main__abc': -1 |
| 102 | 'main__xyz': -1 |
| 103 | 'builtin__println': 10 |
| 104 | }) |
| 105 | validate_output(@FN, '-profile-fns main__abc', sfile, { |
| 106 | 'main__main': -1 |
| 107 | 'main__abc': 1 |
| 108 | 'main__xyz': 2 |
| 109 | 'builtin__println': 10 |
| 110 | }) |
| 111 | validate_output(@FN, '-profile-fns main__xyz', sfile, { |
| 112 | 'main__main': -1 |
| 113 | 'main__abc': -1 |
| 114 | 'main__xyz': 2 |
| 115 | 'builtin__println': 10 |
| 116 | }) |
| 117 | } |
| 118 | |
| 119 | fn counter_value(lines []string, what string) int { |
| 120 | res := lines.filter(it.contains(what)) |
| 121 | if res.len == 0 { |
| 122 | return -1 |
| 123 | } |
| 124 | return res[0].trim_space().all_before(' ').int() |
| 125 | } |
| 126 | |
| 127 | fn validate_output(fn_name string, vopts string, fsource string, expected map[string]int) []string { |
| 128 | println('> validating ${fn_name} with: `v ${vopts} -profile - run ${fsource}`') |
| 129 | os.chdir(vroot) or {} |
| 130 | program_source := os.join_path(vroot, fsource) |
| 131 | res := |
| 132 | os.execute('${os.quoted_path(vexe)} ${vopts} -profile - run ${os.quoted_path(program_source)}') |
| 133 | assert res.exit_code == 0 |
| 134 | assert res.output.len > 0 |
| 135 | res_lines := res.output.split_into_lines() |
| 136 | for expected_counter_name, expected_counter_value in expected { |
| 137 | produced_value := counter_value(res_lines, expected_counter_name) |
| 138 | println(' counter_name: ${expected_counter_name}') |
| 139 | assert produced_value == expected_counter_value |
| 140 | } |
| 141 | return res_lines |
| 142 | } |
| 143 | |