vxx2 / vlib / v / gen / c / profile.v
96 lines · 91 sloc · 4.44 KB · 7134f481ebb818f54fc8da194d9a0453ced1a75e
Raw
1module c
2
3import v.ast
4
5pub struct ProfileCounterMeta {
6 fn_name string
7 vpc_name string
8 vpc_calls string
9}
10
11fn (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 // Prefix the counter names with a unique per-function index. Without it the derived
23 // names collide: a function `…__lower`'s call counter is `vpc_…__lower_calls` (u64),
24 // which is identical to a function `…__lower_calls`'s time accumulator `vpc_…__lower_calls`
25 // (double) — a "redefinition with a different type" C error. The same holds for the
26 // `_only_current` suffix. The index makes every base name unambiguous.
27 fn_profile_counter_name := 'vpc_${g.pcs.len}_${cfn_name}'
28 fn_profile_counter_name_calls := '${fn_profile_counter_name}_calls'
29 g.writeln('')
30 should_restore_v__profile_enabled := g.pref.profile_fns.len > 0
31 && cfn_name in g.pref.profile_fns
32 if should_restore_v__profile_enabled {
33 $if trace_profile_fns ? {
34 eprintln('> profile_fn | ${g.pref.profile_fns} | ${cfn_name}')
35 }
36 g.writeln('\tbool _prev_v__profile_enabled = v__profile_enabled;')
37 g.writeln('\tv__profile_enabled = true;')
38 }
39 g.writeln('\tdouble _PROF_FN_START = ${measure_fn_name}();')
40 g.writeln('\tdouble _PROF_PREV_MEASURED_TIME = prof_measured_time;')
41 g.writeln('if(v__profile_enabled) { ${fn_profile_counter_name_calls}++; } // ${fn_name}')
42 g.writeln('')
43 g.defer_profile_code = '\tif(v__profile_enabled) { \n\t\tdouble _PROF_ELAPSED = ${measure_fn_name}() - _PROF_FN_START;\n'
44 g.defer_profile_code += '\t\t${fn_profile_counter_name} += _PROF_ELAPSED;\n'
45 g.defer_profile_code += '\t\t${fn_profile_counter_name}_only_current += _PROF_ELAPSED - (prof_measured_time - _PROF_PREV_MEASURED_TIME);\n'
46 g.defer_profile_code += '\t\tprof_measured_time = _PROF_PREV_MEASURED_TIME + _PROF_ELAPSED;\n\t}'
47 if should_restore_v__profile_enabled {
48 g.defer_profile_code += '\n\t\tv__profile_enabled = _prev_v__profile_enabled;'
49 }
50 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;')
51 g.pcs << ProfileCounterMeta{
52 fn_name: cfn_name
53 vpc_name: fn_profile_counter_name
54 vpc_calls: fn_profile_counter_name_calls
55 }
56 }
57}
58
59pub fn (mut g Gen) gen_vprint_profile_stats() {
60 g.pcs_declarations.writeln('void vprint_profile_stats(){')
61 fstring := '"%14llu %14.3fms %14.3fms %14.0fns %s \\n"'
62 g.pcs_declarations.writeln('\tf64 f = 1.0;')
63 if g.pref.os == .windows {
64 // QueryPerformanceCounter() / QueryPerformanceFrequency()
65 // https://learn.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps
66 g.pcs_declarations.writeln('\tu64 freq_time = 0;')
67 g.pcs_declarations.writeln('\tQueryPerformanceFrequency(((voidptr)(&freq_time)));')
68 g.pcs_declarations.writeln('\tf = (f64)1000000000.0/(f64)freq_time;')
69 }
70 if g.pref.profile_file == '-' {
71 for pc_meta in g.pcs {
72 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}" );')
73 }
74 } else {
75 g.pcs_declarations.writeln('\tFILE * fp;')
76 g.pcs_declarations.writeln('\tfp = fopen ("${g.pref.profile_file}", "w+");')
77 for pc_meta in g.pcs {
78 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}" );')
79 }
80 g.pcs_declarations.writeln('\tfclose(fp);')
81 }
82 g.pcs_declarations.writeln('}')
83 g.pcs_declarations.writeln('')
84 g.pcs_declarations.writeln('void vreset_profile_stats(){')
85 for pc_meta in g.pcs {
86 g.pcs_declarations.writeln('\t${pc_meta.vpc_calls} = 0;')
87 g.pcs_declarations.writeln('\t${pc_meta.vpc_name} = 0.0;')
88 }
89 g.pcs_declarations.writeln('}')
90 g.pcs_declarations.writeln('')
91
92 g.pcs_declarations.writeln('void vprint_profile_stats_on_signal(int sig){')
93 g.pcs_declarations.writeln('\texit(130);')
94 g.pcs_declarations.writeln('}')
95 g.pcs_declarations.writeln('')
96}
97