diff --git a/meson.build b/meson.build index 70b437522..0a5c7b035 100644 --- a/meson.build +++ b/meson.build @@ -73,6 +73,40 @@ if get_option('development') and git.found () branch = output.stdout().strip() endif +# Profiler linking code taken from https://github.com/RidgeRun/gst-inference/blob/master/meson.build +# with some amendments +# 'libprofiler' and 'libtcmalloc' are provided by installing (e.g.) 'google-perftools' and 'libgoogle-pertools-dev' +# Profiling is not active unless either the correct environment variables are set at runtime +# or the profiling is switched on/off in the code using the CPU_PROFILING and HEAP_PROFILING conditional compilation flags +# with the commands Profiler.start () and Profiler.stop () and the corresponding HeapProfiler functions +# It is advisable not to run cpu profiling at the same time as heap profiling +# If meson options are changed then rebuild with 'cd .. && sudo rm -R ./build && build' +# See https://github.com/gperftools/gperftools/blob/master/docs/cpuprofile.adoc +# and https://github.com/gperftools/gperftools/blob/master/docs/heapprofile.adoc +if get_option('cpu-profiling-enabled') + profiler_dep = dependency ('libprofiler') + if(profiler_dep.found()) + message('CPU profiling enabled: Building with profiling support.') + add_global_link_arguments ('-lprofiler', language: 'c') + add_project_arguments ('--define=PROFILING', language: 'vala') + dependencies += profiler_dep + else + message('MESON_FAIL: CPU profiling requested but libprofiler (gperftools) not found.') + endif +endif +if get_option('heap-profiling-enabled') + heap_profiler_dep = dependency ('libtcmalloc') + if(heap_profiler_dep.found()) + message('Heap profiling enabled: Building with heap profiling support.') + add_global_link_arguments ('-ltcmalloc', language: 'c') + add_project_arguments ('--define=HEAP_PROFILING', language: 'vala') + dependencies += heap_profiler_dep + else + message('MESON_FAIL: Heap profiling requested but libtcmalloc (gperftools) not found.') + endif +endif + + subdir('data') subdir('src') if get_option('plugins') diff --git a/meson_options.txt b/meson_options.txt index a18f17e42..95ef478e3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,5 @@ option('plugins', type : 'boolean', value : true) option('have_pkexec', type : 'boolean', value : true, description : 'Allow launching with pkexec. Should not be used in FlatPak') option('development', type : 'boolean', value : false, description : 'Build is a development branch') +option('cpu-profiling-enabled', type : 'boolean', value : false, description: 'Enable cpu profiling') +option('heap-profiling-enabled', type : 'boolean', value : false, description: 'Enable heap profiling') diff --git a/src/Application.vala b/src/Application.vala index afbf15e31..ca48a0efa 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -200,7 +200,39 @@ namespace Scratch { } public static int main (string[] args) { +// By default, profile whole app when profiling is enabled in meson_options.txt +// These conditional statements can be moved to profile sections of code +// The gperftools library must be installed (libgoogle-perftools-dev) +// Amend the profile report paths as required +#if PROFILING + // Visualize the cpu profile with e.g. google-pprof --functions --gv /usr/bin/io.elementary.code + // Use --focus= and --ignore= to filter/prune nodes displayed + var profile_path = Path.build_filename (Environment.get_home_dir (), "CpuProfileCodeApplication.prof"); + // Start CPU profiling + Profiler.start (profile_path); + warning ("start cpu profiling - output to %s", profile_path); +#endif +#if HEAP_PROFILING + // NOTE: Heap profiling at this point slows the program down **a lot** It will take tens of seconds to load. + // The output path will have the suffix '.NNNN.heap' appended + // Visualize the profile with e.g. google-pprof --gv /usr/bin/io.elementary.code + // Use --focus= and --ignore= to filter/prune nodes displayed + var heap_profile_path = Path.build_filename (Environment.get_home_dir (), "HeapProfileCodeApplication"); + // Start heap profiling + HeapProfiler.start (heap_profile_path); + warning ("start heap profiling - output to %s", heap_profile_path); +#endif + return new Application ().run (args); + +#if PROFILING + Profiler.stop (); + warning ("stop cpu profiling"); +#endif +#if HEAP_PROFILING + HeapProfiler.stop (); + warning ("stop heap profiling"); +#endif } } } diff --git a/vapi/libprofiler.vapi b/vapi/libprofiler.vapi new file mode 100644 index 000000000..e597a147b --- /dev/null +++ b/vapi/libprofiler.vapi @@ -0,0 +1,9 @@ +[CCode (cheader_filename = "gperftools/profiler.h")] +namespace Profiler { + [CCode (cname = "ProfilerStart")] + public static void start (string path_to_output_file); + [CCode (cname = "ProfilerStop")] + public static void stop (); + [CCode (cname = "ProfilerFlush")] + public static void flush (); +} diff --git a/vapi/libtcmalloc.vapi b/vapi/libtcmalloc.vapi new file mode 100644 index 000000000..35303b7b2 --- /dev/null +++ b/vapi/libtcmalloc.vapi @@ -0,0 +1,9 @@ +[CCode (cheader_filename = "gperftools/heap-profiler.h")] +namespace HeapProfiler { + [CCode (cname = "HeapProfilerStart")] + public static void start (string path_to_output_file_profix); + [CCode (cname = "HeapProfilerStop")] + public static void stop (); + [CCode (cname = "HeapProfilerDump")] + public static void dump (string reason); +}