blob: a29e8d1e18136ec2b88cce19f03ee3073f8d6340 [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#include <string>
#include <glog/logging.h>
#ifdef ENABLE_GPERFTOOLS
#include <gperftools/profiler.h>
#endif
#include "process/future.hpp"
#include "process/help.hpp"
#include "process/http.hpp"
#include "process/profiler.hpp"
#include "stout/format.hpp"
#include "stout/option.hpp"
#include "stout/os.hpp"
#include "stout/os/strerror.hpp"
namespace process {
#ifdef ENABLE_GPERFTOOLS
namespace {
constexpr char PROFILE_FILE[] = "perftools.out";
} // namespace {
#endif
const std::string Profiler::START_HELP()
{
return HELP(
TLDR(
"Start profiling."),
DESCRIPTION(
"Start to use google perftools do profiling."),
AUTHENTICATION(true));
}
const std::string Profiler::STOP_HELP()
{
return HELP(
TLDR(
"Stops profiling."),
DESCRIPTION(
"Stop to use google perftools do profiling."),
AUTHENTICATION(true));
}
Future<http::Response> Profiler::start(
const http::Request& request,
const Option<http::authentication::Principal>&)
{
#ifdef ENABLE_GPERFTOOLS
const Option<std::string>
enableProfiler = os::getenv("LIBPROCESS_ENABLE_PROFILER");
if (enableProfiler.isNone() || enableProfiler.get() != "1") {
return http::BadRequest(
"The profiler is not enabled. To enable the profiler, libprocess "
"must be started with LIBPROCESS_ENABLE_PROFILER=1 in the "
"environment.\n");
}
if (started) {
return http::BadRequest("Profiler already started.\n");
}
LOG(INFO) << "Starting Profiler";
// WARNING: If using libunwind < 1.0.1, profiling should not be used, as
// there are reports of crashes.
// WARNING: If using libunwind 1.0.1, profiling should not be turned on
// when it's possible for new threads to be created.
// This may cause a deadlock. The workaround used in libprocess is described
// here:
// https://groups.google.com/d/topic/google-perftools/Df10Uy4Djrg/discussion
// NOTE: We have not tested this with libunwind > 1.0.1.
if (!ProfilerStart(PROFILE_FILE)) {
Try<std::string> error =
strings::format("Failed to start profiler: %s", os::strerror(errno));
LOG(ERROR) << error.get();
return http::InternalServerError(error.get());
}
started = true;
return http::OK("Profiler started.\n");
#else
return http::BadRequest(
"Perftools is disabled. To enable perftools, "
"configure libprocess with --enable-perftools.\n");
#endif
}
Future<http::Response> Profiler::stop(
const http::Request& request,
const Option<http::authentication::Principal>&)
{
#ifdef ENABLE_GPERFTOOLS
if (!started) {
return http::BadRequest("Profiler not running.\n");
}
LOG(INFO) << "Stopping Profiler";
ProfilerStop();
http::OK response;
response.type = response.PATH;
response.path = "perftools.out";
response.headers["Content-Type"] = "application/octet-stream";
response.headers["Content-Disposition"] =
strings::format("attachment; filename=%s", PROFILE_FILE).get();
started = false;
return response;
#else
return http::BadRequest(
"Perftools is disabled. To enable perftools, "
"configure libprocess with --enable-perftools.\n");
#endif
}
} // namespace process {