| 1 | module c |
| 2 | |
| 3 | import v.ast |
| 4 | |
| 5 | pub struct ProfileCounterMeta { |
| 6 | fn_name string |
| 7 | vpc_name string |
| 8 | vpc_calls string |
| 9 | } |
| 10 | |
| 11 | fn (mut g Gen) profile_fn(fn_decl ast.FnDecl) { |
| 12 | if g.pref.profile_no_inline && fn_decl.attrs.contains('inline') { |
| 13 | g.defer_profile_code = '' |
| 14 | return |
| 15 | } |
| 16 | fn_name := fn_decl.name |
| 17 | cfn_name := g.last_fn_c_name |
| 18 | if fn_name.starts_with('time.vpc_now') || fn_name.starts_with('v.profile.') { |
| 19 | g.defer_profile_code = '' |
| 20 | } else { |
| 21 | measure_fn_name := if g.pref.os == .macos { 'time__vpc_now_darwin' } else { 'time__vpc_now' } |
| 22 | fn_profile_counter_name := 'vpc_${cfn_name}' |
| 23 | fn_profile_counter_name_calls := '${fn_profile_counter_name}_calls' |
| 24 | g.writeln('') |
| 25 | should_restore_v__profile_enabled := g.pref.profile_fns.len > 0 |
| 26 | && cfn_name in g.pref.profile_fns |
| 27 | if should_restore_v__profile_enabled { |
| 28 | $if trace_profile_fns ? { |
| 29 | eprintln('> profile_fn | ${g.pref.profile_fns} | ${cfn_name}') |
| 30 | } |
| 31 | g.writeln('\tbool _prev_v__profile_enabled = v__profile_enabled;') |
| 32 | g.writeln('\tv__profile_enabled = true;') |
| 33 | } |
| 34 | g.writeln('\tdouble _PROF_FN_START = ${measure_fn_name}();') |
| 35 | g.writeln('\tdouble _PROF_PREV_MEASURED_TIME = prof_measured_time;') |
| 36 | g.writeln('if(v__profile_enabled) { ${fn_profile_counter_name_calls}++; } // ${fn_name}') |
| 37 | g.writeln('') |
| 38 | g.defer_profile_code = '\tif(v__profile_enabled) { \n\t\tdouble _PROF_ELAPSED = ${measure_fn_name}() - _PROF_FN_START;\n' |
| 39 | g.defer_profile_code += '\t\t${fn_profile_counter_name} += _PROF_ELAPSED;\n' |
| 40 | g.defer_profile_code += '\t\t${fn_profile_counter_name}_only_current += _PROF_ELAPSED - (prof_measured_time - _PROF_PREV_MEASURED_TIME);\n' |
| 41 | g.defer_profile_code += '\t\tprof_measured_time = _PROF_PREV_MEASURED_TIME + _PROF_ELAPSED;\n\t}' |
| 42 | if should_restore_v__profile_enabled { |
| 43 | g.defer_profile_code += '\n\t\tv__profile_enabled = _prev_v__profile_enabled;' |
| 44 | } |
| 45 | g.pcs_declarations.writeln('double ${fn_profile_counter_name} = 0.0; double ${fn_profile_counter_name}_only_current = 0.0; u64 ${fn_profile_counter_name_calls} = 0;') |
| 46 | g.pcs << ProfileCounterMeta{ |
| 47 | fn_name: cfn_name |
| 48 | vpc_name: fn_profile_counter_name |
| 49 | vpc_calls: fn_profile_counter_name_calls |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | pub fn (mut g Gen) gen_vprint_profile_stats() { |
| 55 | g.pcs_declarations.writeln('void vprint_profile_stats(){') |
| 56 | fstring := '"%14llu %14.3fms %14.3fms %14.0fns %s \\n"' |
| 57 | g.pcs_declarations.writeln('\tf64 f = 1.0;') |
| 58 | if g.pref.os == .windows { |
| 59 | // QueryPerformanceCounter() / QueryPerformanceFrequency() |
| 60 | // https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps |
| 61 | g.pcs_declarations.writeln('\tu64 freq_time = 0;') |
| 62 | g.pcs_declarations.writeln('\tQueryPerformanceFrequency(((voidptr)(&freq_time)));') |
| 63 | g.pcs_declarations.writeln('\tf = (f64)1000000000.0/(f64)freq_time;') |
| 64 | } |
| 65 | if g.pref.profile_file == '-' { |
| 66 | for pc_meta in g.pcs { |
| 67 | g.pcs_declarations.writeln('\tif (${pc_meta.vpc_calls}) printf(${fstring}, ${pc_meta.vpc_calls}, (${pc_meta.vpc_name}*f)/1000000.0, (${pc_meta.vpc_name}_only_current*f)/1000000.0, (${pc_meta.vpc_name}*f)/${pc_meta.vpc_calls}, "${pc_meta.fn_name}" );') |
| 68 | } |
| 69 | } else { |
| 70 | g.pcs_declarations.writeln('\tFILE * fp;') |
| 71 | g.pcs_declarations.writeln('\tfp = fopen ("${g.pref.profile_file}", "w+");') |
| 72 | for pc_meta in g.pcs { |
| 73 | g.pcs_declarations.writeln('\tif (${pc_meta.vpc_calls}) fprintf(fp, ${fstring}, ${pc_meta.vpc_calls}, (${pc_meta.vpc_name}*f)/1000000.0, (${pc_meta.vpc_name}_only_current*f)/1000000.0, (${pc_meta.vpc_name}*f)/${pc_meta.vpc_calls}, "${pc_meta.fn_name}" );') |
| 74 | } |
| 75 | g.pcs_declarations.writeln('\tfclose(fp);') |
| 76 | } |
| 77 | g.pcs_declarations.writeln('}') |
| 78 | g.pcs_declarations.writeln('') |
| 79 | g.pcs_declarations.writeln('void vreset_profile_stats(){') |
| 80 | for pc_meta in g.pcs { |
| 81 | g.pcs_declarations.writeln('\t${pc_meta.vpc_calls} = 0;') |
| 82 | g.pcs_declarations.writeln('\t${pc_meta.vpc_name} = 0.0;') |
| 83 | } |
| 84 | g.pcs_declarations.writeln('}') |
| 85 | g.pcs_declarations.writeln('') |
| 86 | |
| 87 | g.pcs_declarations.writeln('void vprint_profile_stats_on_signal(int sig){') |
| 88 | g.pcs_declarations.writeln('\texit(130);') |
| 89 | g.pcs_declarations.writeln('}') |
| 90 | g.pcs_declarations.writeln('') |
| 91 | } |
| 92 | |