1 // Copyright 2014-2017 the openage authors. See copying.md for legal info.
2 
3 #include "externalprofiler.h"
4 
5 #include <string>
6 
7 #include "../config.h"
8 
9 #if WITH_GPERFTOOLS_PROFILER
10 #include <gperftools/profiler.h>
11 #endif
12 
13 #include "subprocess.h"
14 #include "os.h"
15 #include "../log/log.h"
16 
17 
18 namespace openage {
19 namespace util {
20 
21 
ExternalProfiler()22 ExternalProfiler::ExternalProfiler()
23 	:
24 	currently_profiling{false},
25 	can_profile{WITH_GPERFTOOLS_PROFILER} {}
26 
27 
28 const char *const ExternalProfiler::profiling_filename = "/tmp/openage-gperftools-cpuprofile";
29 const char *const ExternalProfiler::profiling_pdf_filename = "/tmp/openage-gperftools-cpuprofile.pdf";
30 
31 
start()32 void ExternalProfiler::start() {
33 	if (not this->can_profile) {
34 		log::log(MSG(err) << "Can not profile: gperftools is missing");
35 		return;
36 	}
37 
38 	if (this->currently_profiling) {
39 		log::log(MSG(info) << "Profiler is already running");
40 		return;
41 	}
42 
43 	log::log(MSG(info) << "Starting profiler; writing data to " << this->profiling_filename);
44 
45 	this->currently_profiling = true;
46 #if WITH_GPERFTOOLS_PROFILER
47 	ProfilerStart(this->profiling_filename);
48 #endif
49 }
50 
51 
stop()52 void ExternalProfiler::stop() {
53 	if (not this->can_profile) {
54 		log::log(MSG(err) << "Can not profile: gperftools is missing");
55 		return;
56 	}
57 
58 	if (not this->currently_profiling) {
59 		log::log(MSG(err) << "Profiler is not currently running");
60 		return;
61 	}
62 
63 	this->currently_profiling = false;
64 #if WITH_GPERFTOOLS_PROFILER
65 	ProfilerStop();
66 #endif
67 
68 	log::log(MSG(info) << "Profiler stopped; data written to " << this->profiling_filename);
69 }
70 
71 
show_results()72 void ExternalProfiler::show_results() {
73 	if (not this->can_profile) {
74 		log::log(MSG(err) << "Can not profile: gperftools is missing");
75 		return;
76 	}
77 
78 	if (this->currently_profiling) {
79 		log::log(MSG(warn) << "Profiler is currently running; trying to show results anyway");
80 	}
81 
82 #if WITH_GPERFTOOLS_PROFILER
83 	std::string pprof_path = subprocess::which("google-pprof");
84 
85 	// fallback to pprof
86 	if (pprof_path.size() == 0) {
87 		pprof_path = subprocess::which("pprof");
88 	}
89 
90 	if (pprof_path.size() == 0) {
91 		log::log(ERR << "Can not process profiling results: google-pprof or pprof not found in PATH");
92 		return;
93 	}
94 
95 	int retval = subprocess::call(
96 		{
97 			pprof_path.c_str(),
98 			"--pdf",
99 			"--",
100 			os::self_exec_filename().c_str(),
101 			this->profiling_filename,
102 			nullptr
103 		},
104 		true,
105 		this->profiling_pdf_filename);
106 
107 	if (retval != 0) {
108 		log::log(MSG(err) << "Profile analysis failed: " << retval);
109 		return;
110 	}
111 
112 	retval = os::execute_file(this->profiling_pdf_filename);
113 
114 	if (retval != 0) {
115 		log::log(MSG(err) <<
116 			"Could not view profiling visualization " <<
117 			this->profiling_pdf_filename << ": " << retval);
118 		return;
119 	}
120 #endif
121 }
122 
123 } // namespace util
124 } // namespace openage
125