mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 09:16:05 +00:00
Revert "Revert D109159 "[amdgpu] Enable selection of s_cselect_b64
.""
This reverts commit 859ebca744e634dcc89a2294ffa41574f947bd62. The change contained many unrelated changes and e.g. restored unit test failes for the old lld port.
This commit is contained in:
parent
dde7388ad5
commit
085f078307
@ -1,460 +0,0 @@
|
||||
//===--- HIP.cpp - HIP Tool and ToolChain Implementations -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "HIP.h"
|
||||
#include "AMDGPU.h"
|
||||
#include "CommonArgs.h"
|
||||
#include "clang/Basic/Cuda.h"
|
||||
#include "clang/Basic/TargetID.h"
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Driver/InputInfo.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "llvm/Support/Alignment.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/TargetParser.h"
|
||||
|
||||
using namespace clang::driver;
|
||||
using namespace clang::driver::toolchains;
|
||||
using namespace clang::driver::tools;
|
||||
using namespace clang;
|
||||
using namespace llvm::opt;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define NULL_FILE "nul"
|
||||
#else
|
||||
#define NULL_FILE "/dev/null"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
const unsigned HIPCodeObjectAlign = 4096;
|
||||
} // namespace
|
||||
|
||||
void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
|
||||
const InputInfoList &Inputs,
|
||||
const InputInfo &Output,
|
||||
const llvm::opt::ArgList &Args) const {
|
||||
// Construct lld command.
|
||||
// The output from ld.lld is an HSA code object file.
|
||||
ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", "-shared",
|
||||
"-plugin-opt=-amdgpu-internalize-symbols"};
|
||||
|
||||
auto &TC = getToolChain();
|
||||
auto &D = TC.getDriver();
|
||||
assert(!Inputs.empty() && "Must have at least one input.");
|
||||
bool IsThinLTO = D.getLTOMode(/*IsOffload=*/true) == LTOK_Thin;
|
||||
addLTOOptions(TC, Args, LldArgs, Output, Inputs[0], IsThinLTO);
|
||||
|
||||
// Extract all the -m options
|
||||
std::vector<llvm::StringRef> Features;
|
||||
amdgpu::getAMDGPUTargetFeatures(D, TC.getTriple(), Args, Features);
|
||||
|
||||
// Add features to mattr such as cumode
|
||||
std::string MAttrString = "-plugin-opt=-mattr=";
|
||||
for (auto OneFeature : unifyTargetFeatures(Features)) {
|
||||
MAttrString.append(Args.MakeArgString(OneFeature));
|
||||
if (OneFeature != Features.back())
|
||||
MAttrString.append(",");
|
||||
}
|
||||
if (!Features.empty())
|
||||
LldArgs.push_back(Args.MakeArgString(MAttrString));
|
||||
|
||||
// ToDo: Remove this option after AMDGPU backend supports ISA-level linking.
|
||||
// Since AMDGPU backend currently does not support ISA-level linking, all
|
||||
// called functions need to be imported.
|
||||
if (IsThinLTO)
|
||||
LldArgs.push_back(Args.MakeArgString("-plugin-opt=-force-import-all"));
|
||||
|
||||
for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
|
||||
LldArgs.push_back(
|
||||
Args.MakeArgString(Twine("-plugin-opt=") + A->getValue(0)));
|
||||
}
|
||||
|
||||
if (C.getDriver().isSaveTempsEnabled())
|
||||
LldArgs.push_back("-save-temps");
|
||||
|
||||
addLinkerCompressDebugSectionsOption(TC, Args, LldArgs);
|
||||
|
||||
LldArgs.append({"-o", Output.getFilename()});
|
||||
for (auto Input : Inputs)
|
||||
LldArgs.push_back(Input.getFilename());
|
||||
|
||||
if (Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
|
||||
false))
|
||||
llvm::for_each(TC.getHIPDeviceLibs(Args), [&](auto BCFile) {
|
||||
LldArgs.push_back(Args.MakeArgString(BCFile.Path));
|
||||
});
|
||||
|
||||
const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
|
||||
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
|
||||
Lld, LldArgs, Inputs, Output));
|
||||
}
|
||||
|
||||
// Construct a clang-offload-bundler command to bundle code objects for
|
||||
// different GPU's into a HIP fat binary.
|
||||
void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
|
||||
StringRef OutputFileName, const InputInfoList &Inputs,
|
||||
const llvm::opt::ArgList &Args, const Tool& T) {
|
||||
// Construct clang-offload-bundler command to bundle object files for
|
||||
// for different GPU archs.
|
||||
ArgStringList BundlerArgs;
|
||||
BundlerArgs.push_back(Args.MakeArgString("-type=o"));
|
||||
BundlerArgs.push_back(
|
||||
Args.MakeArgString("-bundle-align=" + Twine(HIPCodeObjectAlign)));
|
||||
|
||||
// ToDo: Remove the dummy host binary entry which is required by
|
||||
// clang-offload-bundler.
|
||||
std::string BundlerTargetArg = "-targets=host-x86_64-unknown-linux";
|
||||
std::string BundlerInputArg = "-inputs=" NULL_FILE;
|
||||
|
||||
// For code object version 2 and 3, the offload kind in bundle ID is 'hip'
|
||||
// for backward compatibility. For code object version 4 and greater, the
|
||||
// offload kind in bundle ID is 'hipv4'.
|
||||
std::string OffloadKind = "hip";
|
||||
if (getAMDGPUCodeObjectVersion(C.getDriver(), Args) >= 4)
|
||||
OffloadKind = OffloadKind + "v4";
|
||||
for (const auto &II : Inputs) {
|
||||
const auto* A = II.getAction();
|
||||
BundlerTargetArg = BundlerTargetArg + "," + OffloadKind +
|
||||
"-amdgcn-amd-amdhsa--" +
|
||||
StringRef(A->getOffloadingArch()).str();
|
||||
BundlerInputArg = BundlerInputArg + "," + II.getFilename();
|
||||
}
|
||||
BundlerArgs.push_back(Args.MakeArgString(BundlerTargetArg));
|
||||
BundlerArgs.push_back(Args.MakeArgString(BundlerInputArg));
|
||||
|
||||
std::string Output = std::string(OutputFileName);
|
||||
auto BundlerOutputArg =
|
||||
Args.MakeArgString(std::string("-outputs=").append(Output));
|
||||
BundlerArgs.push_back(BundlerOutputArg);
|
||||
|
||||
const char *Bundler = Args.MakeArgString(
|
||||
T.getToolChain().GetProgramPath("clang-offload-bundler"));
|
||||
C.addCommand(std::make_unique<Command>(
|
||||
JA, T, ResponseFileSupport::None(), Bundler, BundlerArgs, Inputs,
|
||||
InputInfo(&JA, Args.MakeArgString(Output))));
|
||||
}
|
||||
|
||||
/// Add Generated HIP Object File which has device images embedded into the
|
||||
/// host to the argument list for linking. Using MC directives, embed the
|
||||
/// device code and also define symbols required by the code generation so that
|
||||
/// the image can be retrieved at runtime.
|
||||
void AMDGCN::Linker::constructGenerateObjFileFromHIPFatBinary(
|
||||
Compilation &C, const InputInfo &Output,
|
||||
const InputInfoList &Inputs, const ArgList &Args,
|
||||
const JobAction &JA) const {
|
||||
const ToolChain &TC = getToolChain();
|
||||
std::string Name =
|
||||
std::string(llvm::sys::path::stem(Output.getFilename()));
|
||||
|
||||
// Create Temp Object File Generator,
|
||||
// Offload Bundled file and Bundled Object file.
|
||||
// Keep them if save-temps is enabled.
|
||||
const char *McinFile;
|
||||
const char *BundleFile;
|
||||
if (C.getDriver().isSaveTempsEnabled()) {
|
||||
McinFile = C.getArgs().MakeArgString(Name + ".mcin");
|
||||
BundleFile = C.getArgs().MakeArgString(Name + ".hipfb");
|
||||
} else {
|
||||
auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin");
|
||||
McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin));
|
||||
auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb");
|
||||
BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb));
|
||||
}
|
||||
constructHIPFatbinCommand(C, JA, BundleFile, Inputs, Args, *this);
|
||||
|
||||
// Create a buffer to write the contents of the temp obj generator.
|
||||
std::string ObjBuffer;
|
||||
llvm::raw_string_ostream ObjStream(ObjBuffer);
|
||||
|
||||
// Add MC directives to embed target binaries. We ensure that each
|
||||
// section and image is 16-byte aligned. This is not mandatory, but
|
||||
// increases the likelihood of data to be aligned with a cache block
|
||||
// in several main host machines.
|
||||
ObjStream << "# HIP Object Generator\n";
|
||||
ObjStream << "# *** Automatically generated by Clang ***\n";
|
||||
ObjStream << " .protected __hip_fatbin\n";
|
||||
ObjStream << " .type __hip_fatbin,@object\n";
|
||||
ObjStream << " .section .hip_fatbin,\"a\",@progbits\n";
|
||||
ObjStream << " .globl __hip_fatbin\n";
|
||||
ObjStream << " .p2align " << llvm::Log2(llvm::Align(HIPCodeObjectAlign))
|
||||
<< "\n";
|
||||
ObjStream << "__hip_fatbin:\n";
|
||||
ObjStream << " .incbin \"" << BundleFile << "\"\n";
|
||||
ObjStream.flush();
|
||||
|
||||
// Dump the contents of the temp object file gen if the user requested that.
|
||||
// We support this option to enable testing of behavior with -###.
|
||||
if (C.getArgs().hasArg(options::OPT_fhip_dump_offload_linker_script))
|
||||
llvm::errs() << ObjBuffer;
|
||||
|
||||
// Open script file and write the contents.
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None);
|
||||
|
||||
if (EC) {
|
||||
C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
|
||||
return;
|
||||
}
|
||||
|
||||
Objf << ObjBuffer;
|
||||
|
||||
ArgStringList McArgs{"-o", Output.getFilename(),
|
||||
McinFile, "--filetype=obj"};
|
||||
const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc"));
|
||||
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
|
||||
Mc, McArgs, Inputs, Output));
|
||||
}
|
||||
|
||||
// For amdgcn the inputs of the linker job are device bitcode and output is
|
||||
// object file. It calls llvm-link, opt, llc, then lld steps.
|
||||
void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
const InputInfo &Output,
|
||||
const InputInfoList &Inputs,
|
||||
const ArgList &Args,
|
||||
const char *LinkingOutput) const {
|
||||
if (Inputs.size() > 0 &&
|
||||
Inputs[0].getType() == types::TY_Image &&
|
||||
JA.getType() == types::TY_Object)
|
||||
return constructGenerateObjFileFromHIPFatBinary(C, Output, Inputs, Args, JA);
|
||||
|
||||
if (JA.getType() == types::TY_HIP_FATBIN)
|
||||
return constructHIPFatbinCommand(C, JA, Output.getFilename(), Inputs, Args, *this);
|
||||
|
||||
return constructLldCommand(C, JA, Inputs, Output, Args);
|
||||
}
|
||||
|
||||
HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple,
|
||||
const ToolChain &HostTC, const ArgList &Args)
|
||||
: ROCMToolChain(D, Triple, Args), HostTC(HostTC) {
|
||||
// Lookup binaries into the driver directory, this is used to
|
||||
// discover the clang-offload-bundler executable.
|
||||
getProgramPaths().push_back(getDriver().Dir);
|
||||
}
|
||||
|
||||
void HIPToolChain::addClangTargetOptions(
|
||||
const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
Action::OffloadKind DeviceOffloadingKind) const {
|
||||
HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
|
||||
|
||||
assert(DeviceOffloadingKind == Action::OFK_HIP &&
|
||||
"Only HIP offloading kinds are supported for GPUs.");
|
||||
|
||||
CC1Args.push_back("-fcuda-is-device");
|
||||
|
||||
if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals,
|
||||
options::OPT_fno_cuda_approx_transcendentals, false))
|
||||
CC1Args.push_back("-fcuda-approx-transcendentals");
|
||||
|
||||
if (!DriverArgs.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
|
||||
false))
|
||||
CC1Args.append({"-mllvm", "-amdgpu-internalize-symbols"});
|
||||
|
||||
StringRef MaxThreadsPerBlock =
|
||||
DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ);
|
||||
if (!MaxThreadsPerBlock.empty()) {
|
||||
std::string ArgStr =
|
||||
std::string("--gpu-max-threads-per-block=") + MaxThreadsPerBlock.str();
|
||||
CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr));
|
||||
}
|
||||
|
||||
CC1Args.push_back("-fcuda-allow-variadic-functions");
|
||||
|
||||
// Default to "hidden" visibility, as object level linking will not be
|
||||
// supported for the foreseeable future.
|
||||
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
|
||||
options::OPT_fvisibility_ms_compat)) {
|
||||
CC1Args.append({"-fvisibility", "hidden"});
|
||||
CC1Args.push_back("-fapply-global-visibility-to-externs");
|
||||
}
|
||||
|
||||
llvm::for_each(getHIPDeviceLibs(DriverArgs), [&](auto BCFile) {
|
||||
CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode"
|
||||
: "-mlink-bitcode-file");
|
||||
CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path));
|
||||
});
|
||||
}
|
||||
|
||||
llvm::opt::DerivedArgList *
|
||||
HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
|
||||
StringRef BoundArch,
|
||||
Action::OffloadKind DeviceOffloadKind) const {
|
||||
DerivedArgList *DAL =
|
||||
HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind);
|
||||
if (!DAL)
|
||||
DAL = new DerivedArgList(Args.getBaseArgs());
|
||||
|
||||
const OptTable &Opts = getDriver().getOpts();
|
||||
|
||||
for (Arg *A : Args) {
|
||||
if (!shouldSkipArgument(A))
|
||||
DAL->append(A);
|
||||
}
|
||||
|
||||
if (!BoundArch.empty()) {
|
||||
DAL->eraseArg(options::OPT_mcpu_EQ);
|
||||
DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mcpu_EQ), BoundArch);
|
||||
checkTargetID(*DAL);
|
||||
}
|
||||
|
||||
return DAL;
|
||||
}
|
||||
|
||||
Tool *HIPToolChain::buildLinker() const {
|
||||
assert(getTriple().getArch() == llvm::Triple::amdgcn);
|
||||
return new tools::AMDGCN::Linker(*this);
|
||||
}
|
||||
|
||||
void HIPToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
|
||||
HostTC.addClangWarningOptions(CC1Args);
|
||||
}
|
||||
|
||||
ToolChain::CXXStdlibType
|
||||
HIPToolChain::GetCXXStdlibType(const ArgList &Args) const {
|
||||
return HostTC.GetCXXStdlibType(Args);
|
||||
}
|
||||
|
||||
void HIPToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
||||
ArgStringList &CC1Args) const {
|
||||
HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args);
|
||||
}
|
||||
|
||||
void HIPToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args,
|
||||
ArgStringList &CC1Args) const {
|
||||
HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args);
|
||||
}
|
||||
|
||||
void HIPToolChain::AddIAMCUIncludeArgs(const ArgList &Args,
|
||||
ArgStringList &CC1Args) const {
|
||||
HostTC.AddIAMCUIncludeArgs(Args, CC1Args);
|
||||
}
|
||||
|
||||
void HIPToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
|
||||
ArgStringList &CC1Args) const {
|
||||
RocmInstallation.AddHIPIncludeArgs(DriverArgs, CC1Args);
|
||||
}
|
||||
|
||||
SanitizerMask HIPToolChain::getSupportedSanitizers() const {
|
||||
// The HIPToolChain only supports sanitizers in the sense that it allows
|
||||
// sanitizer arguments on the command line if they are supported by the host
|
||||
// toolchain. The HIPToolChain will actually ignore any command line
|
||||
// arguments for any of these "supported" sanitizers. That means that no
|
||||
// sanitization of device code is actually supported at this time.
|
||||
//
|
||||
// This behavior is necessary because the host and device toolchains
|
||||
// invocations often share the command line, so the device toolchain must
|
||||
// tolerate flags meant only for the host toolchain.
|
||||
return HostTC.getSupportedSanitizers();
|
||||
}
|
||||
|
||||
VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D,
|
||||
const ArgList &Args) const {
|
||||
return HostTC.computeMSVCVersion(D, Args);
|
||||
}
|
||||
|
||||
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
|
||||
HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
|
||||
llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs;
|
||||
if (DriverArgs.hasArg(options::OPT_nogpulib))
|
||||
return {};
|
||||
ArgStringList LibraryPaths;
|
||||
|
||||
// Find in --hip-device-lib-path and HIP_LIBRARY_PATH.
|
||||
for (auto Path : RocmInstallation.getRocmDeviceLibPathArg())
|
||||
LibraryPaths.push_back(DriverArgs.MakeArgString(Path));
|
||||
|
||||
addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");
|
||||
|
||||
// Maintain compatability with --hip-device-lib.
|
||||
auto BCLibArgs = DriverArgs.getAllArgValues(options::OPT_hip_device_lib_EQ);
|
||||
if (!BCLibArgs.empty()) {
|
||||
llvm::for_each(BCLibArgs, [&](StringRef BCName) {
|
||||
StringRef FullName;
|
||||
for (std::string LibraryPath : LibraryPaths) {
|
||||
SmallString<128> Path(LibraryPath);
|
||||
llvm::sys::path::append(Path, BCName);
|
||||
FullName = Path;
|
||||
if (llvm::sys::fs::exists(FullName)) {
|
||||
BCLibs.push_back(FullName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
getDriver().Diag(diag::err_drv_no_such_file) << BCName;
|
||||
});
|
||||
} else {
|
||||
if (!RocmInstallation.hasDeviceLibrary()) {
|
||||
getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
|
||||
return {};
|
||||
}
|
||||
StringRef GpuArch = getGPUArch(DriverArgs);
|
||||
assert(!GpuArch.empty() && "Must have an explicit GPU arch.");
|
||||
|
||||
// If --hip-device-lib is not set, add the default bitcode libraries.
|
||||
if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
|
||||
options::OPT_fno_gpu_sanitize, false)) {
|
||||
auto AsanRTL = RocmInstallation.getAsanRTLPath();
|
||||
if (AsanRTL.empty()) {
|
||||
unsigned DiagID = getDriver().getDiags().getCustomDiagID(
|
||||
DiagnosticsEngine::Error,
|
||||
"AMDGPU address sanitizer runtime library (asanrtl) is not found. "
|
||||
"Please install ROCm device library which supports address "
|
||||
"sanitizer");
|
||||
getDriver().Diag(DiagID);
|
||||
return {};
|
||||
} else
|
||||
BCLibs.push_back({AsanRTL.str(), /*ShouldInternalize=*/false});
|
||||
}
|
||||
|
||||
// Add the HIP specific bitcode library.
|
||||
BCLibs.push_back(RocmInstallation.getHIPPath());
|
||||
|
||||
// Add common device libraries like ocml etc.
|
||||
for (auto N : getCommonDeviceLibNames(DriverArgs, GpuArch.str()))
|
||||
BCLibs.push_back(StringRef(N));
|
||||
|
||||
// Add instrument lib.
|
||||
auto InstLib =
|
||||
DriverArgs.getLastArgValue(options::OPT_gpu_instrument_lib_EQ);
|
||||
if (InstLib.empty())
|
||||
return BCLibs;
|
||||
if (llvm::sys::fs::exists(InstLib))
|
||||
BCLibs.push_back(InstLib);
|
||||
else
|
||||
getDriver().Diag(diag::err_drv_no_such_file) << InstLib;
|
||||
}
|
||||
|
||||
return BCLibs;
|
||||
}
|
||||
|
||||
void HIPToolChain::checkTargetID(const llvm::opt::ArgList &DriverArgs) const {
|
||||
auto PTID = getParsedTargetID(DriverArgs);
|
||||
if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) {
|
||||
getDriver().Diag(clang::diag::err_drv_bad_target_id)
|
||||
<< PTID.OptionalTargetID.getValue();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(PTID.OptionalFeatures && "Invalid return from getParsedTargetID");
|
||||
auto &FeatureMap = PTID.OptionalFeatures.getValue();
|
||||
// Sanitizer is not supported with xnack-.
|
||||
if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize,
|
||||
options::OPT_fno_gpu_sanitize, false)) {
|
||||
auto Loc = FeatureMap.find("xnack");
|
||||
if (Loc != FeatureMap.end() && !Loc->second) {
|
||||
auto &Diags = getDriver().getDiags();
|
||||
auto DiagID = Diags.getCustomDiagID(
|
||||
DiagnosticsEngine::Error,
|
||||
"'-fgpu-sanitize' is not compatible with offload arch '%0'. "
|
||||
"Use an offload arch without 'xnack-' instead");
|
||||
Diags.Report(DiagID) << PTID.OptionalTargetID.getValue();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
//===--- HIP.h - HIP ToolChain Implementations ------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H
|
||||
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H
|
||||
|
||||
#include "clang/Driver/ToolChain.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "AMDGPU.h"
|
||||
|
||||
namespace clang {
|
||||
namespace driver {
|
||||
|
||||
namespace tools {
|
||||
|
||||
namespace AMDGCN {
|
||||
// Construct command for creating HIP fatbin.
|
||||
void constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
|
||||
StringRef OutputFileName, const InputInfoList &Inputs,
|
||||
const llvm::opt::ArgList &TCArgs, const Tool& T);
|
||||
|
||||
// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with
|
||||
// device library, then compiles it to ISA in a shared object.
|
||||
class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
|
||||
public:
|
||||
Linker(const ToolChain &TC) : Tool("AMDGCN::Linker", "amdgcn-link", TC) {}
|
||||
|
||||
bool hasIntegratedCPP() const override { return false; }
|
||||
|
||||
void ConstructJob(Compilation &C, const JobAction &JA,
|
||||
const InputInfo &Output, const InputInfoList &Inputs,
|
||||
const llvm::opt::ArgList &TCArgs,
|
||||
const char *LinkingOutput) const override;
|
||||
|
||||
private:
|
||||
|
||||
void constructLldCommand(Compilation &C, const JobAction &JA,
|
||||
const InputInfoList &Inputs, const InputInfo &Output,
|
||||
const llvm::opt::ArgList &Args) const;
|
||||
|
||||
// Construct command for creating Object from HIP fatbin.
|
||||
void constructGenerateObjFileFromHIPFatBinary(Compilation &C,
|
||||
const InputInfo &Output,
|
||||
const InputInfoList &Inputs,
|
||||
const llvm::opt::ArgList &Args,
|
||||
const JobAction &JA) const;
|
||||
};
|
||||
|
||||
} // end namespace AMDGCN
|
||||
} // end namespace tools
|
||||
|
||||
namespace toolchains {
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY HIPToolChain final : public ROCMToolChain {
|
||||
public:
|
||||
HIPToolChain(const Driver &D, const llvm::Triple &Triple,
|
||||
const ToolChain &HostTC, const llvm::opt::ArgList &Args);
|
||||
|
||||
const llvm::Triple *getAuxTriple() const override {
|
||||
return &HostTC.getTriple();
|
||||
}
|
||||
|
||||
llvm::opt::DerivedArgList *
|
||||
TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
|
||||
Action::OffloadKind DeviceOffloadKind) const override;
|
||||
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args,
|
||||
Action::OffloadKind DeviceOffloadKind) const override;
|
||||
void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override;
|
||||
CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override;
|
||||
void
|
||||
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
void AddClangCXXStdlibIncludeArgs(
|
||||
const llvm::opt::ArgList &Args,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
|
||||
llvm::opt::ArgStringList &CC1Args) const override;
|
||||
llvm::SmallVector<BitCodeLibraryInfo, 12>
|
||||
getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override;
|
||||
|
||||
SanitizerMask getSupportedSanitizers() const override;
|
||||
|
||||
VersionTuple
|
||||
computeMSVCVersion(const Driver *D,
|
||||
const llvm::opt::ArgList &Args) const override;
|
||||
|
||||
unsigned GetDefaultDwarfVersion() const override { return 5; }
|
||||
|
||||
const ToolChain &HostTC;
|
||||
void checkTargetID(const llvm::opt::ArgList &DriverArgs) const override;
|
||||
|
||||
protected:
|
||||
Tool *buildLinker() const override;
|
||||
};
|
||||
|
||||
} // end namespace toolchains
|
||||
} // end namespace driver
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HIP_H
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
'version': 0,
|
||||
'roots': [
|
||||
{ 'name': '@DIR@', 'type': 'directory',
|
||||
'contents': [
|
||||
{ 'name': 'only-virtual-file.blacklist', 'type': 'file',
|
||||
'external-contents': '@REAL_FILE@'
|
||||
},
|
||||
{ 'name': 'invalid-virtual-file.blacklist', 'type': 'file',
|
||||
'external-contents': '@NONEXISTENT_FILE@'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// RUN: %clang_cc1 -fsanitize=alignment -fsanitize-recover=alignment -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_alignment_assumption" --check-prefixes=CHECK
|
||||
|
||||
// CHECK-LABEL: @baseline
|
||||
void *baseline(void *x) {
|
||||
// CHECK: call void @__ubsan_handle_alignment_assumption(
|
||||
return __builtin_assume_aligned(x, 1);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: blacklist_0
|
||||
__attribute__((no_sanitize("undefined"))) void *blacklist_0(void *x) {
|
||||
return __builtin_assume_aligned(x, 1);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: blacklist_1
|
||||
__attribute__((no_sanitize("alignment"))) void *blacklist_1(void *x) {
|
||||
return __builtin_assume_aligned(x, 1);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: dont_ignore_volatile_ptrs
|
||||
void *dont_ignore_volatile_ptrs(void * volatile x) {
|
||||
// CHECK: call void @__ubsan_handle_alignment_assumption(
|
||||
return __builtin_assume_aligned(x, 1);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: ignore_volatiles
|
||||
void *ignore_volatiles(volatile void * x) {
|
||||
return __builtin_assume_aligned(x, 1);
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
// RUN: %clang_cc1 -x c -fsanitize=pointer-overflow -fsanitize-recover=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow"
|
||||
// RUN: %clang_cc1 -x c -fno-delete-null-pointer-checks -fsanitize=pointer-overflow -fsanitize-recover=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow"
|
||||
|
||||
// RUN: %clang_cc1 -x c++ -fsanitize=pointer-overflow -fsanitize-recover=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow"
|
||||
// RUN: %clang_cc1 -x c++ -fno-delete-null-pointer-checks -fsanitize=pointer-overflow -fsanitize-recover=pointer-overflow -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s -implicit-check-not="call void @__ubsan_handle_pointer_overflow"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// CHECK-LABEL: @baseline
|
||||
char *baseline(char *base, unsigned long offset) {
|
||||
// CHECK: call void @__ubsan_handle_pointer_overflow(
|
||||
return base + offset;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @blacklist_0
|
||||
__attribute__((no_sanitize("undefined"))) char *blacklist_0(char *base, unsigned long offset) {
|
||||
return base + offset;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @blacklist_1
|
||||
__attribute__((no_sanitize("pointer-overflow"))) char *blacklist_1(char *base, unsigned long offset) {
|
||||
return base + offset;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ignore_non_default_address_space
|
||||
__attribute__((address_space(1))) char *ignore_non_default_address_space(__attribute__((address_space(1))) char *base, unsigned long offset) {
|
||||
return base + offset;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,28 +0,0 @@
|
||||
// Verify ubsan doesn't emit checks for blacklisted functions and files
|
||||
// RUN: echo "fun:hash" > %t-func.blacklist
|
||||
// RUN: echo "src:%s" | sed -e 's/\\/\\\\/g' > %t-file.blacklist
|
||||
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow -emit-llvm %s -o - | FileCheck %s --check-prefix=DEFAULT
|
||||
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow -fsanitize-blacklist=%t-func.blacklist -emit-llvm %s -o - | FileCheck %s --check-prefix=FUNC
|
||||
// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow -fsanitize-blacklist=%t-file.blacklist -emit-llvm %s -o - | FileCheck %s --check-prefix=FILE
|
||||
|
||||
unsigned i;
|
||||
|
||||
// DEFAULT: @hash
|
||||
// FUNC: @hash
|
||||
// FILE: @hash
|
||||
unsigned hash() {
|
||||
// DEFAULT: call {{.*}}void @__ubsan
|
||||
// FUNC-NOT: call {{.*}}void @__ubsan
|
||||
// FILE-NOT: call {{.*}}void @__ubsan
|
||||
return i * 37;
|
||||
}
|
||||
|
||||
// DEFAULT: @add
|
||||
// FUNC: @add
|
||||
// FILE: @add
|
||||
unsigned add() {
|
||||
// DEFAULT: call {{.*}}void @__ubsan
|
||||
// FUNC: call {{.*}}void @__ubsan
|
||||
// FILE-NOT: call {{.*}}void @__ubsan
|
||||
return i + 1;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
|
||||
|
||||
// Check that blacklisting cfi and cfi-vcall work correctly
|
||||
// RUN: echo "[cfi-vcall]" > %t.vcall.txt
|
||||
// RUN: echo "type:std::*" >> %t.vcall.txt
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.vcall.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
|
||||
//
|
||||
// RUN: echo "[cfi]" > %t.cfi.txt
|
||||
// RUN: echo "type:std::*" >> %t.cfi.txt
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.cfi.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTD %s
|
||||
|
||||
// Check that blacklisting non-vcall modes does not affect vcalls
|
||||
// RUN: echo "[cfi-icall|cfi-nvcall|cfi-cast-strict|cfi-derived-cast|cfi-unrelated-cast]" > %t.other.txt
|
||||
// RUN: echo "type:std::*" >> %t.other.txt
|
||||
// RUN: %clang_cc1 -triple %itanium_abi_triple -fvisibility hidden -fms-extensions -fsanitize=cfi-vcall -fsanitize-blacklist=%t.other.txt -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOBL %s
|
||||
|
||||
struct S1 {
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
namespace std {
|
||||
|
||||
struct S2 {
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}}s1f
|
||||
// NOBL: llvm.type.test
|
||||
// NOSTD: llvm.type.test
|
||||
void s1f(S1 *s1) {
|
||||
s1->f();
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}}s2f
|
||||
// NOBL: llvm.type.test
|
||||
// NOSTD-NOT: llvm.type.test
|
||||
void s2f(std::S2 *s2) {
|
||||
s2->f();
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
// RUN: %clang -Xclang -fexperimental-debug-variable-locations -fsyntax-only -disable-llvm-passes %s
|
||||
int main() {}
|
@ -1,22 +0,0 @@
|
||||
// RUN: %clang_cc1 -triple aarch64 -verify -fsyntax-only %s
|
||||
|
||||
__attribute__((target("branch-protection=foo"))) // expected-error {{invalid or misplaced branch protection specification 'foo'}}
|
||||
void badvalue0() {}
|
||||
|
||||
__attribute__((target("branch-protection=+bti"))) // expected-error {{invalid or misplaced branch protection specification '<empty>'}}
|
||||
void badvalue1() {}
|
||||
|
||||
__attribute__((target("branch-protection=bti+"))) // expected-error {{invalid or misplaced branch protection specification '<empty>'}}
|
||||
void badvalue2() {}
|
||||
|
||||
__attribute__((target("branch-protection=pac-ret+bkey"))) // expected-error {{invalid or misplaced branch protection specification 'bkey'}}
|
||||
void badvalue3() {}
|
||||
|
||||
__attribute__((target("branch-protection=bti+leaf"))) // expected-error {{invalid or misplaced branch protection specification 'leaf'}}
|
||||
void badoption0() {}
|
||||
|
||||
__attribute__((target("branch-protection=bti+leaf+pac-ret"))) // expected-error {{invalid or misplaced branch protection specification 'leaf'}}
|
||||
void badorder0() {}
|
||||
|
||||
__attribute__ ((target("branch-protection=pac-ret+bti+leaf"))) // expected-error {{invalid or misplaced branch protection specification 'leaf'}}
|
||||
void badorder1() {}
|
@ -1,29 +0,0 @@
|
||||
# TODO(phosek): We should use the runtimes build instead configured with
|
||||
# LLVM_ENABLE_RUNTIMES=libcxxabi;libcxx to avoid duplication of logic.
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.4)
|
||||
project(custom-libcxx C CXX)
|
||||
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
# Build static libcxxabi.
|
||||
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
|
||||
set(LIBCXXABI_ENABLE_EXCEPTIONS ON CACHE BOOL "")
|
||||
set(LIBCXXABI_HERMETIC_STATIC_LIBRARY ON CACHE STRING "")
|
||||
set(LIBCXXABI_LIBCXX_PATH ${COMPILER_RT_LIBCXX_PATH} CACHE PATH "")
|
||||
set(LIBCXXABI_INCLUDE_TESTS OFF CACHE BOOL "")
|
||||
add_subdirectory(${COMPILER_RT_LIBCXXABI_PATH} ${CMAKE_CURRENT_BINARY_DIR}/cxxabi)
|
||||
|
||||
# Build static libcxx without exceptions.
|
||||
set(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY OFF CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_SHARED OFF CACHE BOOL "")
|
||||
set(LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
|
||||
set(LIBCXX_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")
|
||||
|
||||
# Use above libcxxabi.
|
||||
set(LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "")
|
||||
set(LIBCXX_CXX_ABI_INTREE 1)
|
||||
set(LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
|
||||
set(LIBCXX_CXX_ABI_INCLUDE_PATHS ${COMPILER_RT_LIBCXXABI_PATH}/include CACHE PATH "")
|
||||
|
||||
add_subdirectory(${COMPILER_RT_LIBCXX_PATH} ${CMAKE_CURRENT_BINARY_DIR}/cxx)
|
@ -1,110 +0,0 @@
|
||||
//===-- sanitizer_persistent_allocator.h ------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// A fast memory allocator that does not support free() nor realloc().
|
||||
// All allocations are forever.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SANITIZER_PERSISTENT_ALLOCATOR_H
|
||||
#define SANITIZER_PERSISTENT_ALLOCATOR_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#include "sanitizer_mutex.h"
|
||||
#include "sanitizer_atomic.h"
|
||||
#include "sanitizer_common.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
|
||||
template <typename T>
|
||||
class PersistentAllocator {
|
||||
public:
|
||||
T *alloc(uptr count = 1);
|
||||
uptr allocated() const { return atomic_load_relaxed(&mapped_size); }
|
||||
|
||||
void TestOnlyUnmap();
|
||||
|
||||
private:
|
||||
T *tryAlloc(uptr count);
|
||||
T *refillAndAlloc(uptr count);
|
||||
mutable StaticSpinMutex mtx; // Protects alloc of new blocks.
|
||||
atomic_uintptr_t region_pos; // Region allocator for Node's.
|
||||
atomic_uintptr_t region_end;
|
||||
atomic_uintptr_t mapped_size;
|
||||
|
||||
struct BlockInfo {
|
||||
const BlockInfo *next;
|
||||
uptr ptr;
|
||||
uptr size;
|
||||
};
|
||||
const BlockInfo *curr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T *PersistentAllocator<T>::tryAlloc(uptr count) {
|
||||
// Optimisic lock-free allocation, essentially try to bump the region ptr.
|
||||
for (;;) {
|
||||
uptr cmp = atomic_load(®ion_pos, memory_order_acquire);
|
||||
uptr end = atomic_load(®ion_end, memory_order_acquire);
|
||||
uptr size = count * sizeof(T);
|
||||
if (cmp == 0 || cmp + size > end)
|
||||
return nullptr;
|
||||
if (atomic_compare_exchange_weak(®ion_pos, &cmp, cmp + size,
|
||||
memory_order_acquire))
|
||||
return reinterpret_cast<T *>(cmp);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T *PersistentAllocator<T>::alloc(uptr count) {
|
||||
// First, try to allocate optimisitically.
|
||||
T *s = tryAlloc(count);
|
||||
if (LIKELY(s))
|
||||
return s;
|
||||
return refillAndAlloc(count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T *PersistentAllocator<T>::refillAndAlloc(uptr count) {
|
||||
// If failed, lock, retry and alloc new superblock.
|
||||
SpinMutexLock l(&mtx);
|
||||
for (;;) {
|
||||
T *s = tryAlloc(count);
|
||||
if (s)
|
||||
return s;
|
||||
atomic_store(®ion_pos, 0, memory_order_relaxed);
|
||||
uptr size = count * sizeof(T) + sizeof(BlockInfo);
|
||||
uptr allocsz = RoundUpTo(Max<uptr>(size, 64u * 1024u), GetPageSizeCached());
|
||||
uptr mem = (uptr)MmapOrDie(allocsz, "stack depot");
|
||||
BlockInfo *new_block = (BlockInfo *)(mem + allocsz) - 1;
|
||||
new_block->next = curr;
|
||||
new_block->ptr = mem;
|
||||
new_block->size = allocsz;
|
||||
curr = new_block;
|
||||
|
||||
atomic_fetch_add(&mapped_size, allocsz, memory_order_relaxed);
|
||||
|
||||
allocsz -= sizeof(BlockInfo);
|
||||
atomic_store(®ion_end, mem + allocsz, memory_order_release);
|
||||
atomic_store(®ion_pos, mem, memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void PersistentAllocator<T>::TestOnlyUnmap() {
|
||||
while (curr) {
|
||||
uptr mem = curr->ptr;
|
||||
uptr allocsz = curr->size;
|
||||
curr = curr->next;
|
||||
UnmapOrDie((void *)mem, allocsz);
|
||||
}
|
||||
internal_memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // SANITIZER_PERSISTENT_ALLOCATOR_H
|
@ -1,59 +0,0 @@
|
||||
//===-- tsan_update_shadow_word.inc -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
// Body of the hottest inner loop.
|
||||
// If we wrap this body into a function, compilers (both gcc and clang)
|
||||
// produce sligtly less efficient code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
do {
|
||||
const unsigned kAccessSize = 1 << kAccessSizeLog;
|
||||
u64 *sp = &shadow_mem[idx];
|
||||
old = LoadShadow(sp);
|
||||
if (LIKELY(old.IsZero())) {
|
||||
if (!stored) {
|
||||
StoreIfNotYetStored(sp, &store_word);
|
||||
stored = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// is the memory access equal to the previous?
|
||||
if (LIKELY(Shadow::Addr0AndSizeAreEqual(cur, old))) {
|
||||
// same thread?
|
||||
if (LIKELY(Shadow::TidsAreEqual(old, cur))) {
|
||||
if (LIKELY(old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))) {
|
||||
StoreIfNotYetStored(sp, &store_word);
|
||||
stored = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (HappensBefore(old, thr)) {
|
||||
if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic)) {
|
||||
StoreIfNotYetStored(sp, &store_word);
|
||||
stored = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (LIKELY(old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic)))
|
||||
break;
|
||||
goto RACE;
|
||||
}
|
||||
// Do the memory access intersect?
|
||||
if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
|
||||
if (Shadow::TidsAreEqual(old, cur))
|
||||
break;
|
||||
if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
|
||||
break;
|
||||
if (LIKELY(HappensBefore(old, thr)))
|
||||
break;
|
||||
goto RACE;
|
||||
}
|
||||
// The accesses do not intersect.
|
||||
break;
|
||||
} while (0);
|
@ -1,51 +0,0 @@
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
// Tests whether scaling the Entropic scheduling weight based on input execution
|
||||
// time is effective or not. Inputs of size less than 7 will take at least 100
|
||||
// microseconds more than inputs of size greater than or equal to 7. Inputs of
|
||||
// size greater than 7 in the corpus should be favored by the exec-time-scaled
|
||||
// Entropic scheduling policy than the input of size less than 7 in the corpus,
|
||||
// eventually finding the crashing input with less executions.
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
|
||||
static volatile int Sink;
|
||||
static volatile int *Nil = nullptr;
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
if (Size > 10)
|
||||
return 0; // To make the test quicker.
|
||||
|
||||
if (Size < 7) {
|
||||
// execute a lot slower than the crashing input below.
|
||||
size_t ExecTimeUSec = 100;
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(ExecTimeUSec));
|
||||
Sink = 7;
|
||||
|
||||
if (Size > 0 && Data[0] == 0xaa && Size > 1 && Data[1] == 0xbb &&
|
||||
Size > 2 && Data[2] == 0xcc && Size > 3 && Data[3] == 0xdd &&
|
||||
Size > 4 && Data[4] == 0xee && Size > 5 && Data[5] == 0xff)
|
||||
Sink += 7;
|
||||
}
|
||||
|
||||
// Give unique coverage for each input of size (7, 8, 9, 10)
|
||||
if (Size == 7)
|
||||
Sink = -7;
|
||||
|
||||
if (Size == 8)
|
||||
Sink = -8;
|
||||
|
||||
if (Size == 9)
|
||||
Sink = -9;
|
||||
|
||||
if (Size == 10)
|
||||
Sink = -10;
|
||||
|
||||
if (Sink < 0 && Data[0] == 0xab && Data[1] == 0xcd)
|
||||
*Nil = 42; // crash.
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
REQUIRES: linux, x86_64
|
||||
RUN: %cpp_compiler %S/EntropicScalePerExecTimeTest.cpp -o %t-EntropicScalePerExecTimeTest
|
||||
RUN: not %run %t-EntropicScalePerExecTimeTest -entropic=1 -entropic_scale_per_exec_time=1 -seed=1 -runs=200000 -max_len=10
|
||||
|
||||
# Without -entropic_scale_per_exec_time=1, the crash takes longer to find since
|
||||
# the slow path is explored first. This test is disabled because it sometimes
|
||||
# finds the bug under certain configs.
|
||||
DISABLED: %run %t-EntropicScalePerExecTimeTest -entropic=1 -seed=1 -runs=200000 -max_len=10
|
@ -1,10 +0,0 @@
|
||||
// Check mem_info_cache_entries option.
|
||||
|
||||
// RUN: %clangxx_memprof -O0 %s -o %t && %env_memprof_opts=log_path=stderr:mem_info_cache_entries=15:print_mem_info_cache_miss_rate=1:print_mem_info_cache_miss_rate_details=1 %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: Set 14 miss rate: 0 / {{.*}} = 0.00%
|
||||
// CHECK-NOT: Set
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// Check print_mem_info_cache_miss_rate and
|
||||
// print_mem_info_cache_miss_rate_details options.
|
||||
|
||||
// RUN: %clangxx_memprof -O0 %s -o %t
|
||||
// RUN: %env_memprof_opts=log_path=stderr:print_mem_info_cache_miss_rate=1 %run %t 2>&1 | FileCheck %s
|
||||
// RUN: %env_memprof_opts=log_path=stderr:print_mem_info_cache_miss_rate=1:print_mem_info_cache_miss_rate_details=1 %run %t 2>&1 | FileCheck %s --check-prefix=DETAILS
|
||||
|
||||
// CHECK: Overall miss rate: 0 / {{.*}} = 0.00%
|
||||
// DETAILS: Set 0 miss rate: 0 / {{.*}} = 0.00%
|
||||
// DETAILS: Set 16380 miss rate: 0 / {{.*}} = 0.00%
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
// RUN: %clang -fsanitize=alignment -fno-sanitize-recover=alignment -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --implicit-check-not=" assumption "
|
||||
|
||||
// RUN: rm -f %tmp
|
||||
// RUN: echo "[alignment]" >> %tmp
|
||||
// RUN: echo "fun:main" >> %tmp
|
||||
// RUN: %clang -fsanitize=alignment -fno-sanitize-recover=alignment -fsanitize-ignorelist=%tmp -O0 %s -o %t && %run %t 2>&1
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
char *ptr = (char *)malloc(2);
|
||||
|
||||
__builtin_assume_aligned(ptr + 1, 0x8000);
|
||||
// CHECK: {{.*}}alignment-assumption-ignorelist.cpp:[[@LINE-1]]:32: runtime error: assumption of 32768 byte alignment for pointer of type 'char *' failed
|
||||
// CHECK: 0x{{.*}}: note: address is {{.*}} aligned, misalignment offset is {{.*}} byte
|
||||
|
||||
free(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
set(LLVM_BUILD_32_BITS ON CACHE BOOL "")
|
@ -1,52 +0,0 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___MEMORY_POINTER_SAFETY_H
|
||||
#define _LIBCPP___MEMORY_POINTER_SAFETY_H
|
||||
|
||||
#include <__config>
|
||||
#include <cstddef>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if !defined(_LIBCPP_CXX03_LANG)
|
||||
|
||||
enum class pointer_safety : unsigned char {
|
||||
relaxed,
|
||||
preferred,
|
||||
strict
|
||||
};
|
||||
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
pointer_safety get_pointer_safety() _NOEXCEPT {
|
||||
return pointer_safety::relaxed;
|
||||
}
|
||||
|
||||
_LIBCPP_FUNC_VIS void declare_reachable(void* __p);
|
||||
_LIBCPP_FUNC_VIS void declare_no_pointers(char* __p, size_t __n);
|
||||
_LIBCPP_FUNC_VIS void undeclare_no_pointers(char* __p, size_t __n);
|
||||
_LIBCPP_FUNC_VIS void* __undeclare_reachable(void* __p);
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_Tp*
|
||||
undeclare_reachable(_Tp* __p)
|
||||
{
|
||||
return static_cast<_Tp*>(__undeclare_reachable(__p));
|
||||
}
|
||||
|
||||
#endif // !C++03
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___MEMORY_POINTER_SAFETY_H
|
@ -1,28 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <atomic>
|
||||
|
||||
// Make sure that `std::atomic` doesn't work with `_ExtInt`. The intent is to
|
||||
// disable them for now until their behavior can be designed better later.
|
||||
// See https://reviews.llvm.org/D84049 for details.
|
||||
|
||||
// UNSUPPORTED: apple-clang-12
|
||||
|
||||
// UNSUPPORTED: libcpp-has-no-threads
|
||||
// UNSUPPORTED: c++03
|
||||
|
||||
#include <atomic>
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
// expected-error@atomic:*1 {{_Atomic cannot be applied to integer type '_ExtInt(32)'}}
|
||||
std::atomic<_ExtInt(32)> x(42);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <atomic>
|
||||
|
||||
// Test that including <atomic> fails to compile when _LIBCPP_HAS_NO_THREADS
|
||||
// is defined.
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_HAS_NO_THREADS
|
||||
|
||||
#include <atomic>
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// XFAIL: libcpp-has-no-threads
|
||||
|
||||
#ifdef _LIBCPP_HAS_NO_THREADS
|
||||
#error This should be XFAILed for the purpose of detecting that the LIT feature\
|
||||
'libcpp-has-no-threads' is available iff _LIBCPP_HAS_NO_THREADS is defined
|
||||
#endif
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03
|
||||
|
||||
// <algorithm>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct Incomplete;
|
||||
template<class T> struct Holder { T t; };
|
||||
|
||||
template<class>
|
||||
struct Intable {
|
||||
TEST_CONSTEXPR operator int() const { return 1; }
|
||||
};
|
||||
|
||||
struct Tester {
|
||||
using Element = Holder<Incomplete>*;
|
||||
Element data[10];
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool test()
|
||||
{
|
||||
Tester t {};
|
||||
Tester u {};
|
||||
Tester::Element value = nullptr;
|
||||
Intable<Tester::Element> count;
|
||||
|
||||
// THESE RELY ON ADL SWAP IN PRACTICE:
|
||||
// swap_ranges, iter_swap, reverse, rotate, partition
|
||||
// sort, nth_element
|
||||
// pop_heap, sort_heap, partial_sort, partial_sort_copy
|
||||
// next_permutation, prev_permutation
|
||||
// stable_partition, stable_sort, inplace_merge
|
||||
// THESE RELY ON ADL SWAP IN THEORY:
|
||||
// push_heap, make_heap
|
||||
|
||||
(void)std::all_of(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::any_of(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::copy(t.data, t.data+10, u.data);
|
||||
(void)std::copy_n(t.data, count, u.data);
|
||||
(void)std::copy_backward(t.data, t.data+10, u.data+10);
|
||||
(void)std::count(t.data, t.data+10, value);
|
||||
(void)std::count_if(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::distance(t.data, t.data+10);
|
||||
(void)std::fill(t.data, t.data+10, value);
|
||||
(void)std::fill_n(t.data, count, value);
|
||||
(void)std::find_if(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::find_if_not(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::for_each(t.data, t.data+10, [](void*){});
|
||||
#if TEST_STD_VER >= 17
|
||||
(void)std::for_each_n(t.data, count, [](void*){});
|
||||
#endif
|
||||
(void)std::generate(t.data, t.data+10, [](){ return nullptr; });
|
||||
(void)std::generate_n(t.data, count, [](){ return nullptr; });
|
||||
(void)std::is_partitioned(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::move(t.data, t.data+10, u.data);
|
||||
(void)std::move_backward(t.data, t.data+10, u.data+10);
|
||||
(void)std::none_of(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::partition_copy(t.data, t.data+5, u.data, u.data+5, [](void*){ return true; });
|
||||
(void)std::partition_point(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::remove(t.data, t.data+10, value);
|
||||
(void)std::remove_copy(t.data, t.data+10, u.data, value);
|
||||
(void)std::remove_copy_if(t.data, t.data+10, u.data, [](void*){ return true; });
|
||||
(void)std::remove_if(t.data, t.data+10, [](void*){ return true; });
|
||||
(void)std::replace(t.data, t.data+10, value, value);
|
||||
(void)std::replace_copy(t.data, t.data+10, u.data, value, value);
|
||||
(void)std::replace_copy_if(t.data, t.data+10, u.data, [](void*){ return true; }, value);
|
||||
(void)std::replace_if(t.data, t.data+10, [](void*){ return true; }, value);
|
||||
(void)std::reverse_copy(t.data, t.data+10, u.data);
|
||||
(void)std::rotate_copy(t.data, t.data+5, t.data+10, u.data);
|
||||
// TODO: shift_left
|
||||
// TODO: shift_right
|
||||
(void)std::transform(t.data, t.data+10, u.data, [](void*){ return nullptr; });
|
||||
|
||||
// WITHOUT COMPARATORS
|
||||
(void)std::adjacent_find(t.data, t.data+10);
|
||||
(void)std::binary_search(t.data, t.data+10, t.data[5]);
|
||||
(void)std::equal(t.data, t.data+10, u.data);
|
||||
(void)std::equal_range(t.data, t.data+10, t.data[5]);
|
||||
(void)std::find_end(t.data, t.data+10, u.data, u.data+5);
|
||||
(void)std::includes(t.data, t.data+10, u.data, u.data+10);
|
||||
(void)std::is_heap(t.data, t.data+10);
|
||||
(void)std::is_heap_until(t.data, t.data+10);
|
||||
(void)std::is_permutation(t.data, t.data+10, u.data);
|
||||
(void)std::is_sorted(t.data, t.data+10);
|
||||
(void)std::is_sorted_until(t.data, t.data+10);
|
||||
(void)std::lexicographical_compare(t.data, t.data+10, u.data, u.data+10);
|
||||
// TODO: lexicographical_compare_three_way
|
||||
(void)std::lower_bound(t.data, t.data+10, t.data[5]);
|
||||
(void)std::max(value, value);
|
||||
(void)std::max({ value, value });
|
||||
(void)std::max_element(t.data, t.data+10);
|
||||
(void)std::merge(t.data, t.data+5, t.data+5, t.data+10, u.data);
|
||||
(void)std::min(value, value);
|
||||
(void)std::min({ value, value });
|
||||
(void)std::min_element(t.data, t.data+10);
|
||||
(void)std::minmax(value, value);
|
||||
(void)std::minmax({ value, value });
|
||||
(void)std::minmax_element(t.data, t.data+10);
|
||||
(void)std::mismatch(t.data, t.data+10, u.data);
|
||||
(void)std::search(t.data, t.data+10, u.data, u.data+5);
|
||||
(void)std::search_n(t.data, t.data+10, count, value);
|
||||
(void)std::set_difference(t.data, t.data+5, t.data+5, t.data+10, u.data);
|
||||
(void)std::set_intersection(t.data, t.data+5, t.data+5, t.data+10, u.data);
|
||||
(void)std::set_symmetric_difference(t.data, t.data+5, t.data+5, t.data+10, u.data);
|
||||
(void)std::set_union(t.data, t.data+5, t.data+5, t.data+10, u.data);
|
||||
(void)std::unique(t.data, t.data+10);
|
||||
(void)std::unique_copy(t.data, t.data+10, u.data);
|
||||
(void)std::upper_bound(t.data, t.data+10, t.data[5]);
|
||||
#if TEST_STD_VER >= 14
|
||||
(void)std::equal(t.data, t.data+10, u.data, u.data+10);
|
||||
(void)std::is_permutation(t.data, t.data+10, u.data, u.data+10);
|
||||
(void)std::mismatch(t.data, t.data+10, u.data, u.data+10);
|
||||
#endif
|
||||
#if TEST_STD_VER >= 20
|
||||
(void)std::clamp(value, value, value);
|
||||
#endif
|
||||
|
||||
// WITH COMPARATORS
|
||||
(void)std::adjacent_find(t.data, t.data+10, std::equal_to<void*>());
|
||||
(void)std::binary_search(t.data, t.data+10, value, std::less<void*>());
|
||||
(void)std::equal(t.data, t.data+10, u.data, std::equal_to<void*>());
|
||||
(void)std::equal_range(t.data, t.data+10, value, std::less<void*>());
|
||||
(void)std::find_end(t.data, t.data+10, u.data, u.data+5, std::equal_to<void*>());
|
||||
(void)std::includes(t.data, t.data+10, u.data, u.data+10, std::less<void*>());
|
||||
(void)std::is_heap(t.data, t.data+10, std::less<void*>());
|
||||
(void)std::is_heap_until(t.data, t.data+10, std::less<void*>());
|
||||
(void)std::is_permutation(t.data, t.data+10, u.data, std::equal_to<void*>());
|
||||
(void)std::is_sorted(t.data, t.data+10, std::less<void*>());
|
||||
(void)std::is_sorted_until(t.data, t.data+10, std::less<void*>());
|
||||
(void)std::lexicographical_compare(t.data, t.data+10, u.data, u.data+10, std::less<void*>());
|
||||
// TODO: lexicographical_compare_three_way
|
||||
(void)std::lower_bound(t.data, t.data+10, value, std::less<void*>());
|
||||
(void)std::max(value, value, std::less<void*>());
|
||||
(void)std::max({ value, value }, std::less<void*>());
|
||||
(void)std::max_element(t.data, t.data+10, std::less<void*>());
|
||||
(void)std::merge(t.data, t.data+5, t.data+5, t.data+10, u.data, std::less<void*>());
|
||||
(void)std::min(value, value, std::less<void*>());
|
||||
(void)std::min({ value, value }, std::less<void*>());
|
||||
(void)std::min_element(t.data, t.data+10, std::less<void*>());
|
||||
(void)std::minmax(value, value, std::less<void*>());
|
||||
(void)std::minmax({ value, value }, std::less<void*>());
|
||||
(void)std::minmax_element(t.data, t.data+10, std::less<void*>());
|
||||
(void)std::mismatch(t.data, t.data+10, u.data, std::equal_to<void*>());
|
||||
(void)std::search(t.data, t.data+10, u.data, u.data+5, std::equal_to<void*>());
|
||||
(void)std::search_n(t.data, t.data+10, count, value, std::equal_to<void*>());
|
||||
(void)std::set_difference(t.data, t.data+5, t.data+5, t.data+10, u.data, std::less<void*>());
|
||||
(void)std::set_intersection(t.data, t.data+5, t.data+5, t.data+10, u.data, std::less<void*>());
|
||||
(void)std::set_symmetric_difference(t.data, t.data+5, t.data+5, t.data+10, u.data, std::less<void*>());
|
||||
(void)std::set_union(t.data, t.data+5, t.data+5, t.data+10, u.data, std::less<void*>());
|
||||
(void)std::unique(t.data, t.data+10, std::equal_to<void*>());
|
||||
(void)std::unique_copy(t.data, t.data+10, u.data, std::equal_to<void*>());
|
||||
(void)std::upper_bound(t.data, t.data+10, value, std::less<void*>());
|
||||
#if TEST_STD_VER >= 14
|
||||
(void)std::equal(t.data, t.data+10, u.data, u.data+10, std::equal_to<void*>());
|
||||
(void)std::is_permutation(t.data, t.data+10, u.data, u.data+10, std::equal_to<void*>());
|
||||
(void)std::mismatch(t.data, t.data+10, u.data, u.data+10, std::equal_to<void*>());
|
||||
#endif
|
||||
#if TEST_STD_VER >= 20
|
||||
(void)std::clamp(value, value, value, std::less<void*>());
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert(test());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <atomic>
|
||||
|
||||
// template <class T>
|
||||
// struct atomic
|
||||
// {
|
||||
// bool is_lock_free() const volatile noexcept;
|
||||
// bool is_lock_free() const noexcept;
|
||||
// void store(T desr, memory_order m = memory_order_seq_cst) volatile noexcept;
|
||||
// void store(T desr, memory_order m = memory_order_seq_cst) noexcept;
|
||||
// T load(memory_order m = memory_order_seq_cst) const volatile noexcept;
|
||||
// T load(memory_order m = memory_order_seq_cst) const noexcept;
|
||||
// operator T() const volatile noexcept;
|
||||
// operator T() const noexcept;
|
||||
// T exchange(T desr, memory_order m = memory_order_seq_cst) volatile noexcept;
|
||||
// T exchange(T desr, memory_order m = memory_order_seq_cst) noexcept;
|
||||
// bool compare_exchange_weak(T& expc, T desr,
|
||||
// memory_order s, memory_order f) volatile noexcept;
|
||||
// bool compare_exchange_weak(T& expc, T desr, memory_order s, memory_order f) noexcept;
|
||||
// bool compare_exchange_strong(T& expc, T desr,
|
||||
// memory_order s, memory_order f) volatile noexcept;
|
||||
// bool compare_exchange_strong(T& expc, T desr,
|
||||
// memory_order s, memory_order f) noexcept;
|
||||
// bool compare_exchange_weak(T& expc, T desr,
|
||||
// memory_order m = memory_order_seq_cst) volatile noexcept;
|
||||
// bool compare_exchange_weak(T& expc, T desr,
|
||||
// memory_order m = memory_order_seq_cst) noexcept;
|
||||
// bool compare_exchange_strong(T& expc, T desr,
|
||||
// memory_order m = memory_order_seq_cst) volatile noexcept;
|
||||
// bool compare_exchange_strong(T& expc, T desr,
|
||||
// memory_order m = memory_order_seq_cst) noexcept;
|
||||
//
|
||||
// atomic() noexcept = default;
|
||||
// constexpr atomic(T desr) noexcept;
|
||||
// atomic(const atomic&) = delete;
|
||||
// atomic& operator=(const atomic&) = delete;
|
||||
// atomic& operator=(const atomic&) volatile = delete;
|
||||
// T operator=(T) volatile noexcept;
|
||||
// T operator=(T) noexcept;
|
||||
// };
|
||||
|
||||
#include <atomic>
|
||||
#include <new>
|
||||
#include <cassert>
|
||||
#include <thread> // for thread_id
|
||||
#include <chrono> // for nanoseconds
|
||||
|
||||
struct NotTriviallyCopyable {
|
||||
NotTriviallyCopyable ( int i ) : i_(i) {}
|
||||
NotTriviallyCopyable ( const NotTriviallyCopyable &rhs) : i_(rhs.i_) {}
|
||||
int i_;
|
||||
};
|
||||
|
||||
template <class T, class >
|
||||
void test ( T t ) {
|
||||
std::atomic<T> t0(t);
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test(NotTriviallyCopyable(42));
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <vector>
|
||||
|
||||
// iterator insert(const_iterator position, const value_type& x);
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_allocator.h"
|
||||
#include "min_allocator.h"
|
||||
#include "asan_testing.h"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
std::vector<int> v(100);
|
||||
std::vector<int>::iterator i = v.insert(v.cbegin() + 10, 1);
|
||||
assert(v.size() == 101);
|
||||
assert(is_contiguous_container_asan_correct(v));
|
||||
assert(i == v.begin() + 10);
|
||||
int j;
|
||||
for (j = 0; j < 10; ++j)
|
||||
assert(v[j] == 0);
|
||||
assert(v[j] == 1);
|
||||
for (++j; j < 101; ++j)
|
||||
assert(v[j] == 0);
|
||||
}
|
||||
{
|
||||
std::vector<int> v(100);
|
||||
while(v.size() < v.capacity()) v.push_back(0); // force reallocation
|
||||
size_t sz = v.size();
|
||||
std::vector<int>::iterator i = v.insert(v.cbegin() + 10, 1);
|
||||
assert(v.size() == sz + 1);
|
||||
assert(is_contiguous_container_asan_correct(v));
|
||||
assert(i == v.begin() + 10);
|
||||
std::size_t j;
|
||||
for (j = 0; j < 10; ++j)
|
||||
assert(v[j] == 0);
|
||||
assert(v[j] == 1);
|
||||
for (++j; j < v.size(); ++j)
|
||||
assert(v[j] == 0);
|
||||
}
|
||||
{
|
||||
std::vector<int> v(100);
|
||||
while(v.size() < v.capacity()) v.push_back(0);
|
||||
v.pop_back(); v.pop_back(); // force no reallocation
|
||||
size_t sz = v.size();
|
||||
std::vector<int>::iterator i = v.insert(v.cbegin() + 10, 1);
|
||||
assert(v.size() == sz + 1);
|
||||
assert(is_contiguous_container_asan_correct(v));
|
||||
assert(i == v.begin() + 10);
|
||||
std::size_t j;
|
||||
for (j = 0; j < 10; ++j)
|
||||
assert(v[j] == 0);
|
||||
assert(v[j] == 1);
|
||||
for (++j; j < v.size(); ++j)
|
||||
assert(v[j] == 0);
|
||||
}
|
||||
{
|
||||
std::vector<int, limited_allocator<int, 300> > v(100);
|
||||
std::vector<int, limited_allocator<int, 300> >::iterator i = v.insert(v.cbegin() + 10, 1);
|
||||
assert(v.size() == 101);
|
||||
assert(is_contiguous_container_asan_correct(v));
|
||||
assert(i == v.begin() + 10);
|
||||
int j;
|
||||
for (j = 0; j < 10; ++j)
|
||||
assert(v[j] == 0);
|
||||
assert(v[j] == 1);
|
||||
for (++j; j < 101; ++j)
|
||||
assert(v[j] == 0);
|
||||
}
|
||||
#if TEST_STD_VER >= 11
|
||||
{
|
||||
std::vector<int, min_allocator<int>> v(100);
|
||||
std::vector<int, min_allocator<int>>::iterator i = v.insert(v.cbegin() + 10, 1);
|
||||
assert(v.size() == 101);
|
||||
assert(is_contiguous_container_asan_correct(v));
|
||||
assert(i == v.begin() + 10);
|
||||
int j;
|
||||
for (j = 0; j < 10; ++j)
|
||||
assert(v[j] == 0);
|
||||
assert(v[j] == 1);
|
||||
for (++j; j < 101; ++j)
|
||||
assert(v[j] == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// <charconv> feature macros
|
||||
|
||||
/* Constant Value
|
||||
__cpp_lib_to_chars 201611L
|
||||
|
||||
*/
|
||||
|
||||
#include <charconv>
|
||||
#include <cassert>
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
// ensure that the macros that are supposed to be defined in <utility> are defined.
|
||||
|
||||
/*
|
||||
#if !defined(__cpp_lib_fooby)
|
||||
# error "__cpp_lib_fooby is not defined"
|
||||
#elif __cpp_lib_fooby < 201606L
|
||||
# error "__cpp_lib_fooby has an invalid value"
|
||||
#endif
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// <memory_resource> feature macros
|
||||
|
||||
/* Constant Value
|
||||
__cpp_lib_memory_resource 201603L
|
||||
|
||||
*/
|
||||
|
||||
// XFAIL
|
||||
// #include <memory_resource>
|
||||
#include <cassert>
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
// ensure that the macros that are supposed to be defined in <memory_resource> are defined.
|
||||
|
||||
/*
|
||||
#if !defined(__cpp_lib_fooby)
|
||||
# error "__cpp_lib_fooby is not defined"
|
||||
#elif __cpp_lib_fooby < 201606L
|
||||
# error "__cpp_lib_fooby has an invalid value"
|
||||
#endif
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
unsigned int ui = -5;
|
||||
ui = std::abs(ui); // expected-error {{call to 'abs' is ambiguous}}
|
||||
|
||||
unsigned char uc = -5;
|
||||
uc = std::abs(uc); // expected-warning {{taking the absolute value of unsigned type 'unsigned char' has no effect}}
|
||||
|
||||
unsigned short us = -5;
|
||||
us = std::abs(us); // expected-warning {{taking the absolute value of unsigned type 'unsigned short' has no effect}}
|
||||
|
||||
unsigned long ul = -5;
|
||||
ul = std::abs(ul); // expected-error {{call to 'abs' is ambiguous}}
|
||||
|
||||
unsigned long long ull = -5;
|
||||
ull = ::abs(ull); // expected-error {{call to 'abs' is ambiguous}}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// <string_view>
|
||||
|
||||
// template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
|
||||
// basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
|
||||
|
||||
#include <string_view>
|
||||
#include <cassert>
|
||||
|
||||
#include "make_string.h"
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template<class CharT, class Sentinel>
|
||||
constexpr void test() {
|
||||
auto val = MAKE_STRING_VIEW(CharT, "test");
|
||||
auto sv = std::basic_string_view(val.begin(), Sentinel(val.end()));
|
||||
ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
|
||||
assert(sv.size() == val.size());
|
||||
assert(sv.data() == val.data());
|
||||
}
|
||||
|
||||
constexpr void test() {
|
||||
test<char, char*>();
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
test<wchar_t, wchar_t*>();
|
||||
#endif
|
||||
test<char8_t, char8_t*>();
|
||||
test<char16_t, char16_t*>();
|
||||
test<char32_t, char32_t*>();
|
||||
test<char, const char*>();
|
||||
test<char, sized_sentinel<const char*>>();
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
|
||||
// Throwing bad_any_cast is supported starting in macosx10.13
|
||||
// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}}
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class ValueType>
|
||||
// ValueType any_cast(any const &);
|
||||
|
||||
// Try and cast away const.
|
||||
|
||||
#include <any>
|
||||
|
||||
struct TestType {};
|
||||
struct TestType2 {};
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
any a;
|
||||
|
||||
// expected-error@any:* {{drops 'const' qualifier}}
|
||||
// expected-error-re@any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
|
||||
any_cast<TestType &>(static_cast<any const&>(a)); // expected-note {{requested here}}
|
||||
|
||||
// expected-error@any:* {{cannot cast from lvalue of type 'const TestType' to rvalue reference type 'TestType &&'; types are not compatible}}
|
||||
// expected-error-re@any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
|
||||
any_cast<TestType &&>(static_cast<any const&>(a)); // expected-note {{requested here}}
|
||||
|
||||
// expected-error@any:* {{drops 'const' qualifier}}
|
||||
// expected-error-re@any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
|
||||
any_cast<TestType2 &>(static_cast<any const&&>(a)); // expected-note {{requested here}}
|
||||
|
||||
// expected-error@any:* {{cannot cast from lvalue of type 'const TestType2' to rvalue reference type 'TestType2 &&'; types are not compatible}}
|
||||
// expected-error-re@any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
|
||||
any_cast<TestType2 &&>(static_cast<any const&&>(a)); // expected-note {{requested here}}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
|
||||
// Throwing bad_any_cast is supported starting in macosx10.13
|
||||
// UNSUPPORTED: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}}
|
||||
|
||||
// <any>
|
||||
|
||||
// template <class ValueType>
|
||||
// ValueType const any_cast(any const&);
|
||||
//
|
||||
// template <class ValueType>
|
||||
// ValueType any_cast(any &);
|
||||
//
|
||||
// template <class ValueType>
|
||||
// ValueType any_cast(any &&);
|
||||
|
||||
// Test instantiating the any_cast with a non-copyable type.
|
||||
|
||||
#include <any>
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
struct no_copy
|
||||
{
|
||||
no_copy() {}
|
||||
no_copy(no_copy &&) {}
|
||||
no_copy(no_copy const &) = delete;
|
||||
};
|
||||
|
||||
struct no_move {
|
||||
no_move() {}
|
||||
no_move(no_move&&) = delete;
|
||||
no_move(no_move const&) {}
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
any a;
|
||||
// expected-error-re@any:* {{static_assert failed{{.*}} "ValueType is required to be an lvalue reference or a CopyConstructible type"}}
|
||||
// expected-error@any:* {{static_cast from 'no_copy' to 'no_copy' uses deleted function}}
|
||||
any_cast<no_copy>(static_cast<any&>(a)); // expected-note {{requested here}}
|
||||
|
||||
// expected-error-re@any:* {{static_assert failed{{.*}} "ValueType is required to be a const lvalue reference or a CopyConstructible type"}}
|
||||
// expected-error@any:* {{static_cast from 'const no_copy' to 'no_copy' uses deleted function}}
|
||||
any_cast<no_copy>(static_cast<any const&>(a)); // expected-note {{requested here}}
|
||||
|
||||
any_cast<no_copy>(static_cast<any &&>(a)); // OK
|
||||
|
||||
// expected-error-re@any:* {{static_assert failed{{.*}} "ValueType is required to be an rvalue reference or a CopyConstructible type"}}
|
||||
// expected-error@any:* {{static_cast from 'typename remove_reference<no_move &>::type' (aka 'no_move') to 'no_move' uses deleted function}}
|
||||
any_cast<no_move>(static_cast<any &&>(a));
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03
|
||||
|
||||
// <memory>
|
||||
|
||||
// void declare_no_pointers(char* p, size_t n);
|
||||
// void undeclare_no_pointers(char* p, size_t n);
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char* p = new char[10];
|
||||
std::declare_no_pointers(p, 10);
|
||||
std::undeclare_no_pointers(p, 10);
|
||||
delete [] p;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03
|
||||
|
||||
// <memory>
|
||||
|
||||
// void declare_reachable(void* p);
|
||||
// template <class T> T* undeclare_reachable(T* p);
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
int* p = new int;
|
||||
std::declare_reachable(p);
|
||||
assert(std::undeclare_reachable(p) == p);
|
||||
delete p;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <memory>
|
||||
|
||||
// pointer_safety get_pointer_safety();
|
||||
|
||||
// UNSUPPORTED: c++03
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
{
|
||||
static_assert(std::is_enum<std::pointer_safety>::value, "");
|
||||
static_assert(!std::is_convertible<std::pointer_safety, int>::value, "");
|
||||
static_assert(std::is_same<
|
||||
std::underlying_type<std::pointer_safety>::type,
|
||||
unsigned char
|
||||
>::value, "");
|
||||
}
|
||||
{
|
||||
std::pointer_safety r = std::get_pointer_safety();
|
||||
assert(r == std::pointer_safety::relaxed ||
|
||||
r == std::pointer_safety::preferred ||
|
||||
r == std::pointer_safety::strict);
|
||||
}
|
||||
// Regression test for https://llvm.org/PR26961
|
||||
{
|
||||
std::pointer_safety d;
|
||||
d = std::get_pointer_safety();
|
||||
assert(d == std::get_pointer_safety());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX20_REMOVED_TYPE_TRAITS
|
||||
|
||||
// type_traits
|
||||
|
||||
// result_of
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**) {
|
||||
[[maybe_unused]] std::result_of<int (*())()> a; // expected-warning {{'result_of<int (*())()>' is deprecated}}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
// -*- C++ -*-
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SUPPORT_COROUTINE_TYPES_H
|
||||
#define SUPPORT_COROUTINE_TYPES_H
|
||||
|
||||
#include <experimental/coroutine>
|
||||
|
||||
template <typename Ty> struct generator {
|
||||
struct promise_type {
|
||||
Ty current_value;
|
||||
std::experimental::suspend_always yield_value(Ty value) {
|
||||
this->current_value = value;
|
||||
return {};
|
||||
}
|
||||
std::experimental::suspend_always initial_suspend() { return {}; }
|
||||
std::experimental::suspend_always final_suspend() noexcept { return {}; }
|
||||
generator get_return_object() { return generator{this}; };
|
||||
void return_void() {}
|
||||
void unhandled_exception() {}
|
||||
};
|
||||
|
||||
struct iterator {
|
||||
std::experimental::coroutine_handle<promise_type> _Coro;
|
||||
bool _Done;
|
||||
|
||||
iterator(std::experimental::coroutine_handle<promise_type> Coro, bool Done)
|
||||
: _Coro(Coro), _Done(Done) {}
|
||||
|
||||
iterator &operator++() {
|
||||
_Coro.resume();
|
||||
_Done = _Coro.done();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(iterator const &_Right) const {
|
||||
return _Done == _Right._Done;
|
||||
}
|
||||
|
||||
bool operator!=(iterator const &_Right) const { return !(*this == _Right); }
|
||||
|
||||
Ty const &operator*() const { return _Coro.promise().current_value; }
|
||||
|
||||
Ty const *operator->() const { return &(operator*()); }
|
||||
};
|
||||
|
||||
iterator begin() {
|
||||
p.resume();
|
||||
return {p, p.done()};
|
||||
}
|
||||
|
||||
iterator end() { return {p, true}; }
|
||||
|
||||
generator(generator &&rhs) : p(rhs.p) { rhs.p = nullptr; }
|
||||
|
||||
~generator() {
|
||||
if (p)
|
||||
p.destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
explicit generator(promise_type *p)
|
||||
: p(std::experimental::coroutine_handle<promise_type>::from_promise(*p)) {}
|
||||
|
||||
std::experimental::coroutine_handle<promise_type> p;
|
||||
};
|
||||
|
||||
#endif // SUPPORT_COROUTINE_TYPES_H
|
@ -1,59 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef SUPPORT_TRACKED_VALUE_H
|
||||
#define SUPPORT_TRACKED_VALUE_H
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
struct TrackedValue {
|
||||
enum State { CONSTRUCTED, MOVED_FROM, DESTROYED };
|
||||
State state;
|
||||
|
||||
TrackedValue() : state(State::CONSTRUCTED) {}
|
||||
|
||||
TrackedValue(TrackedValue const& t) : state(State::CONSTRUCTED) {
|
||||
assert(t.state != State::MOVED_FROM && "copying a moved-from object");
|
||||
assert(t.state != State::DESTROYED && "copying a destroyed object");
|
||||
}
|
||||
|
||||
#if TEST_STD_VER >= 11
|
||||
TrackedValue(TrackedValue&& t) : state(State::CONSTRUCTED) {
|
||||
assert(t.state != State::MOVED_FROM && "double moving from an object");
|
||||
assert(t.state != State::DESTROYED && "moving from a destroyed object");
|
||||
t.state = State::MOVED_FROM;
|
||||
}
|
||||
#endif
|
||||
|
||||
TrackedValue& operator=(TrackedValue const& t) {
|
||||
assert(state != State::DESTROYED && "copy assigning into destroyed object");
|
||||
assert(t.state != State::MOVED_FROM && "copying a moved-from object");
|
||||
assert(t.state != State::DESTROYED && "copying a destroyed object");
|
||||
state = t.state;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if TEST_STD_VER >= 11
|
||||
TrackedValue& operator=(TrackedValue&& t) {
|
||||
assert(state != State::DESTROYED && "move assigning into destroyed object");
|
||||
assert(t.state != State::MOVED_FROM && "double moving from an object");
|
||||
assert(t.state != State::DESTROYED && "moving from a destroyed object");
|
||||
state = t.state;
|
||||
t.state = State::MOVED_FROM;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
~TrackedValue() {
|
||||
assert(state != State::DESTROYED && "double-destroying an object");
|
||||
state = State::DESTROYED;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SUPPORT_TRACKED_VALUE_H
|
@ -1,5 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
PointerAlignment: Left
|
||||
...
|
@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Checkout LLVM sources
|
||||
git clone --depth=1 https://github.com/llvm/llvm-project.git llvm-project
|
||||
|
||||
# Setup libc++ options
|
||||
if [ -z "$BUILD_32_BITS" ]; then
|
||||
export BUILD_32_BITS=OFF && echo disabling 32 bit build
|
||||
fi
|
||||
|
||||
# Build and install libc++ (Use unstable ABI for better sanitizer coverage)
|
||||
cd ./llvm-project
|
||||
cmake -DCMAKE_C_COMPILER=${C_COMPILER} \
|
||||
-DCMAKE_CXX_COMPILER=${COMPILER} \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DLIBCXX_ABI_UNSTABLE=OFF \
|
||||
-DLLVM_USE_SANITIZER=${LIBCXX_SANITIZER} \
|
||||
-DLLVM_BUILD_32_BITS=${BUILD_32_BITS} \
|
||||
-DLLVM_ENABLE_PROJECTS='libcxx;libcxxabi' \
|
||||
-S llvm -B llvm-build -G "Unix Makefiles"
|
||||
make -C llvm-build -j3 cxx cxxabi
|
||||
sudo make -C llvm-build install-cxx install-cxxabi
|
||||
cd ..
|
@ -1,32 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**System**
|
||||
Which OS, compiler, and compiler version are you using:
|
||||
- OS:
|
||||
- Compiler and version:
|
||||
|
||||
**To reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. sync to commit ...
|
||||
2. cmake/bazel...
|
||||
3. make ...
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[FR]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
@ -1,30 +0,0 @@
|
||||
name: bazel
|
||||
|
||||
on:
|
||||
push: {}
|
||||
pull_request: {}
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: mount bazel cache
|
||||
uses: actions/cache@v2.0.0
|
||||
env:
|
||||
cache-name: bazel-cache
|
||||
with:
|
||||
path: "~/.cache/bazel"
|
||||
key: ${{ env.cache-name }}-${{ runner.os }}-${{ github.ref }}
|
||||
restore-keys: |
|
||||
${{ env.cache-name }}-${{ runner.os }}-main
|
||||
|
||||
- name: build
|
||||
run: |
|
||||
bazel build //:benchmark //:benchmark_main //test/...
|
||||
|
||||
- name: test
|
||||
run: |
|
||||
bazel test --test_output=all //test/...
|
@ -1,44 +0,0 @@
|
||||
name: build-and-test-perfcounters
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
job:
|
||||
# TODO(dominic): Extend this to include compiler and set through env: CC/CXX.
|
||||
name: ${{ matrix.os }}.${{ matrix.build_type }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, ubuntu-16.04, ubuntu-20.04]
|
||||
build_type: ['Release', 'Debug']
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: install libpfm
|
||||
run: sudo apt install libpfm4-dev
|
||||
|
||||
- name: create build environment
|
||||
run: cmake -E make_directory ${{ runner.workspace }}/_build
|
||||
|
||||
- name: configure cmake
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/_build
|
||||
run: cmake -DBENCHMARK_ENABLE_LIBPFM=1 -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
|
||||
- name: build
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/_build
|
||||
run: cmake --build . --config ${{ matrix.build_type }}
|
||||
|
||||
# Skip testing, for now. It seems perf_event_open does not succeed on the
|
||||
# hosting machine, very likely a permissions issue.
|
||||
# TODO(mtrofin): Enable test.
|
||||
# - name: test
|
||||
# shell: bash
|
||||
# working-directory: ${{ runner.workspace }}/_build
|
||||
# run: sudo ctest -C ${{ matrix.build_type }} --rerun-failed --output-on-failure
|
@ -1,110 +0,0 @@
|
||||
name: build-and-test
|
||||
|
||||
on:
|
||||
push: {}
|
||||
pull_request: {}
|
||||
|
||||
jobs:
|
||||
# TODO: add 32-bit builds (g++ and clang++) for ubuntu
|
||||
# (requires g++-multilib and libc6:i386)
|
||||
# TODO: add coverage build (requires lcov)
|
||||
# TODO: add clang + libc++ builds for ubuntu
|
||||
# TODO: add clang + ubsan/asan/msan + libc++ builds for ubuntu
|
||||
job:
|
||||
name: ${{ matrix.os }}.${{ matrix.build_type }}.${{ matrix.compiler }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, ubuntu-16.04, ubuntu-20.04, macos-latest]
|
||||
build_type: ['Release', 'Debug']
|
||||
compiler: [g++, clang++]
|
||||
include:
|
||||
- displayTargetName: windows-latest-release
|
||||
os: windows-latest
|
||||
build_type: 'Release'
|
||||
- displayTargetName: windows-latest-debug
|
||||
os: windows-latest
|
||||
build_type: 'Debug'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: create build environment
|
||||
run: cmake -E make_directory ${{ runner.workspace }}/_build
|
||||
|
||||
- name: configure cmake
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/_build
|
||||
run: >
|
||||
cmake $GITHUB_WORKSPACE
|
||||
-DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
|
||||
- name: build
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/_build
|
||||
run: cmake --build . --config ${{ matrix.build_type }}
|
||||
|
||||
- name: test
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/_build
|
||||
run: ctest -C ${{ matrix.build_type }} -VV
|
||||
|
||||
ubuntu-14_04:
|
||||
name: ubuntu-14.04.${{ matrix.build_type }}.${{ matrix.compiler }}
|
||||
runs-on: [ubuntu-latest]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: ['Release', 'Debug']
|
||||
compiler: [g++-4.8, clang++-3.6]
|
||||
include:
|
||||
- compiler: g++-6
|
||||
build_type: 'Debug'
|
||||
run_tests: true
|
||||
- compiler: g++-6
|
||||
build_type: 'Release'
|
||||
run_tests: true
|
||||
container: ubuntu:14.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: install required bits
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt -y install clang-3.6 cmake3 g++-4.8 git
|
||||
|
||||
- name: install other bits
|
||||
if: ${{ matrix.compiler }} == g++-6
|
||||
run: |
|
||||
sudo apt -y install software-properties-common
|
||||
sudo add-apt-repository -y "ppa:ubuntu-toolchain-r/test"
|
||||
sudo apt update
|
||||
sudo apt -y install g++-6
|
||||
|
||||
- name: create build environment
|
||||
run: cmake -E make_directory $GITHUB_WORKSPACE/_build
|
||||
|
||||
- name: configure cmake
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/_build
|
||||
run: >
|
||||
cmake $GITHUB_WORKSPACE
|
||||
-DBENCHMARK_ENABLE_TESTING=${{ matrix.run_tests }}
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
-DBENCHMARK_DOWNLOAD_DEPENDENCIES=${{ matrix.run_tests }}
|
||||
|
||||
- name: build
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/_build
|
||||
run: cmake --build . --config ${{ matrix.build_type }}
|
||||
|
||||
- name: test
|
||||
if: ${{ matrix.run_tests }}
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}/_build
|
||||
run: ctest -C ${{ matrix.build_type }} -VV
|
@ -1,26 +0,0 @@
|
||||
name: pylint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
pylint:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pylint pylint-exit conan
|
||||
- name: Run pylint
|
||||
run: |
|
||||
pylint `find . -name '*.py'|xargs` || pylint-exit $?
|
@ -1,78 +0,0 @@
|
||||
name: sanitizer
|
||||
|
||||
on:
|
||||
push: {}
|
||||
pull_request: {}
|
||||
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
EXTRA_CXX_FLAGS: "-stdlib=libc++"
|
||||
UBSAN_OPTIONS: "print_stacktrace=1"
|
||||
|
||||
jobs:
|
||||
job:
|
||||
name: ${{ matrix.sanitizer }}.${{ matrix.build_type }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: ['Debug', 'RelWithDebInfo']
|
||||
sanitizer: ['asan', 'ubsan', 'tsan']
|
||||
# TODO: add 'msan' above. currently failing and needs investigation.
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: configure msan env
|
||||
if: matrix.sanitizer == 'msan'
|
||||
run: |
|
||||
echo "EXTRA_FLAGS=-g -O2 -fno-omit-frame-pointer -fsanitize=memory -fsanitize-memory-track-origins" >> $GITHUB_ENV
|
||||
echo "LIBCXX_SANITIZER=MemoryWithOrigins" >> $GITHUB_ENV
|
||||
|
||||
- name: configure ubsan env
|
||||
if: matrix.sanitizer == 'ubsan'
|
||||
run: |
|
||||
echo "EXTRA_FLAGS=-g -O2 -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=all" >> $GITHUB_ENV
|
||||
echo "LIBCXX_SANITIZER=Undefined" >> $GITHUB_ENV
|
||||
|
||||
- name: configure asan env
|
||||
if: matrix.sanitizer == 'asan'
|
||||
run: |
|
||||
echo "EXTRA_FLAGS=-g -O2 -fno-omit-frame-pointer -fsanitize=address -fno-sanitize-recover=all" >> $GITHUB_ENV
|
||||
echo "LIBCXX_SANITIZER=Address" >> $GITHUB_ENV
|
||||
|
||||
- name: configure tsan env
|
||||
if: matrix.sanitizer == 'tsan'
|
||||
run: |
|
||||
echo "EXTRA_FLAGS=-g -O2 -fno-omit-frame-pointer -fsanitize=thread -fno-sanitize-recover=all" >> $GITHUB_ENV
|
||||
echo "LIBCXX_SANITIZER=Thread" >> $GITHUB_ENV
|
||||
|
||||
- name: install llvm stuff
|
||||
run: "${GITHUB_WORKSPACE}/.github/.libcxx-setup.sh"
|
||||
|
||||
- name: create build environment
|
||||
run: cmake -E make_directory ${{ runner.workspace }}/_build
|
||||
|
||||
- name: configure cmake
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/_build
|
||||
run: >
|
||||
cmake $GITHUB_WORKSPACE
|
||||
-DBENCHMARK_ENABLE_ASSEMBLY_TESTS=OFF
|
||||
-DBENCHMARK_ENABLE_LIBPFM=OFF
|
||||
-DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON
|
||||
-DCMAKE_C_COMPILER=${{ env.CC }}
|
||||
-DCMAKE_CXX_COMPILER=${{ env.CXX }}
|
||||
-DCMAKE_C_FLAGS="${{ env.EXTRA_FLAGS }}"
|
||||
-DCMAKE_CXX_FLAGS="${{ env.EXTRA_FLAGS }} ${{ env.EXTRA_CXX_FLAGS }}"
|
||||
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
|
||||
|
||||
- name: build
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/_build
|
||||
run: cmake --build . --config ${{ matrix.build_type }}
|
||||
|
||||
- name: test
|
||||
shell: bash
|
||||
working-directory: ${{ runner.workspace }}/_build
|
||||
run: ctest -C ${{ matrix.build_type }} -VV
|
@ -1,24 +0,0 @@
|
||||
name: test-bindings
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
python_bindings:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install benchmark
|
||||
run:
|
||||
python setup.py install
|
||||
- name: Run example bindings
|
||||
run:
|
||||
python bindings/python/google_benchmark/example.py
|
66
libcxx/utils/google-benchmark/.gitignore
vendored
66
libcxx/utils/google-benchmark/.gitignore
vendored
@ -1,66 +0,0 @@
|
||||
*.a
|
||||
*.so
|
||||
*.so.?*
|
||||
*.dll
|
||||
*.exe
|
||||
*.dylib
|
||||
*.cmake
|
||||
!/cmake/*.cmake
|
||||
!/test/AssemblyTests.cmake
|
||||
*~
|
||||
*.swp
|
||||
*.pyc
|
||||
__pycache__
|
||||
|
||||
# lcov
|
||||
*.lcov
|
||||
/lcov
|
||||
|
||||
# cmake files.
|
||||
/Testing
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
cmake_install.cmake
|
||||
|
||||
# makefiles.
|
||||
Makefile
|
||||
|
||||
# in-source build.
|
||||
bin/
|
||||
lib/
|
||||
/test/*_test
|
||||
|
||||
# exuberant ctags.
|
||||
tags
|
||||
|
||||
# YouCompleteMe configuration.
|
||||
.ycm_extra_conf.pyc
|
||||
|
||||
# ninja generated files.
|
||||
.ninja_deps
|
||||
.ninja_log
|
||||
build.ninja
|
||||
install_manifest.txt
|
||||
rules.ninja
|
||||
|
||||
# bazel output symlinks.
|
||||
bazel-*
|
||||
|
||||
# out-of-source build top-level folders.
|
||||
build/
|
||||
_build/
|
||||
build*/
|
||||
|
||||
# in-source dependencies
|
||||
/googletest/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
CMakeSettings.json
|
||||
|
||||
# Visual Studio Code cache/options directory
|
||||
.vscode/
|
||||
|
||||
# Python build stuff
|
||||
dist/
|
||||
*.egg-info*
|
@ -1,208 +0,0 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: cpp
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- lcov
|
||||
env: COMPILER=g++ C_COMPILER=gcc BUILD_TYPE=Coverage
|
||||
- compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-multilib
|
||||
- libc6:i386
|
||||
env:
|
||||
- COMPILER=g++
|
||||
- C_COMPILER=gcc
|
||||
- BUILD_TYPE=Debug
|
||||
- BUILD_32_BITS=ON
|
||||
- EXTRA_FLAGS="-m32"
|
||||
- compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-multilib
|
||||
- libc6:i386
|
||||
env:
|
||||
- COMPILER=g++
|
||||
- C_COMPILER=gcc
|
||||
- BUILD_TYPE=Release
|
||||
- BUILD_32_BITS=ON
|
||||
- EXTRA_FLAGS="-m32"
|
||||
- compiler: gcc
|
||||
env:
|
||||
- INSTALL_GCC6_FROM_PPA=1
|
||||
- COMPILER=g++-6 C_COMPILER=gcc-6 BUILD_TYPE=Debug
|
||||
- ENABLE_SANITIZER=1
|
||||
- EXTRA_FLAGS="-fno-omit-frame-pointer -g -O2 -fsanitize=undefined,address -fuse-ld=gold"
|
||||
# Clang w/ libc++
|
||||
- compiler: clang
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
clang-3.8
|
||||
env:
|
||||
- INSTALL_GCC6_FROM_PPA=1
|
||||
- COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug
|
||||
- LIBCXX_BUILD=1
|
||||
- EXTRA_CXX_FLAGS="-stdlib=libc++"
|
||||
- compiler: clang
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
clang-3.8
|
||||
env:
|
||||
- INSTALL_GCC6_FROM_PPA=1
|
||||
- COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Release
|
||||
- LIBCXX_BUILD=1
|
||||
- EXTRA_CXX_FLAGS="-stdlib=libc++"
|
||||
# Clang w/ 32bit libc++
|
||||
- compiler: clang
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.8
|
||||
- g++-multilib
|
||||
- libc6:i386
|
||||
env:
|
||||
- INSTALL_GCC6_FROM_PPA=1
|
||||
- COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug
|
||||
- LIBCXX_BUILD=1
|
||||
- BUILD_32_BITS=ON
|
||||
- EXTRA_FLAGS="-m32"
|
||||
- EXTRA_CXX_FLAGS="-stdlib=libc++"
|
||||
# Clang w/ 32bit libc++
|
||||
- compiler: clang
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.8
|
||||
- g++-multilib
|
||||
- libc6:i386
|
||||
env:
|
||||
- INSTALL_GCC6_FROM_PPA=1
|
||||
- COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Release
|
||||
- LIBCXX_BUILD=1
|
||||
- BUILD_32_BITS=ON
|
||||
- EXTRA_FLAGS="-m32"
|
||||
- EXTRA_CXX_FLAGS="-stdlib=libc++"
|
||||
# Clang w/ libc++, ASAN, UBSAN
|
||||
- compiler: clang
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
clang-3.8
|
||||
env:
|
||||
- INSTALL_GCC6_FROM_PPA=1
|
||||
- COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug
|
||||
- LIBCXX_BUILD=1 LIBCXX_SANITIZER="Undefined;Address"
|
||||
- ENABLE_SANITIZER=1
|
||||
- EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=undefined,address -fno-sanitize-recover=all"
|
||||
- EXTRA_CXX_FLAGS="-stdlib=libc++"
|
||||
- UBSAN_OPTIONS=print_stacktrace=1
|
||||
# Clang w/ libc++ and MSAN
|
||||
- compiler: clang
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
clang-3.8
|
||||
env:
|
||||
- INSTALL_GCC6_FROM_PPA=1
|
||||
- COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=Debug
|
||||
- LIBCXX_BUILD=1 LIBCXX_SANITIZER=MemoryWithOrigins
|
||||
- ENABLE_SANITIZER=1
|
||||
- EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=memory -fsanitize-memory-track-origins"
|
||||
- EXTRA_CXX_FLAGS="-stdlib=libc++"
|
||||
# Clang w/ libc++ and MSAN
|
||||
- compiler: clang
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
clang-3.8
|
||||
env:
|
||||
- INSTALL_GCC6_FROM_PPA=1
|
||||
- COMPILER=clang++-3.8 C_COMPILER=clang-3.8 BUILD_TYPE=RelWithDebInfo
|
||||
- LIBCXX_BUILD=1 LIBCXX_SANITIZER=Thread
|
||||
- ENABLE_SANITIZER=1
|
||||
- EXTRA_FLAGS="-g -O2 -fno-omit-frame-pointer -fsanitize=thread -fno-sanitize-recover=all"
|
||||
- EXTRA_CXX_FLAGS="-stdlib=libc++"
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
compiler: clang
|
||||
env:
|
||||
- COMPILER=clang++
|
||||
- BUILD_TYPE=Release
|
||||
- BUILD_32_BITS=ON
|
||||
- EXTRA_FLAGS="-m32"
|
||||
|
||||
before_script:
|
||||
- if [ -n "${LIBCXX_BUILD}" ]; then
|
||||
source .libcxx-setup.sh;
|
||||
fi
|
||||
- if [ -n "${ENABLE_SANITIZER}" ]; then
|
||||
export EXTRA_OPTIONS="-DBENCHMARK_ENABLE_ASSEMBLY_TESTS=OFF";
|
||||
else
|
||||
export EXTRA_OPTIONS="";
|
||||
fi
|
||||
- mkdir -p build && cd build
|
||||
|
||||
before_install:
|
||||
- if [ -z "$BUILD_32_BITS" ]; then
|
||||
export BUILD_32_BITS=OFF && echo disabling 32 bit build;
|
||||
fi
|
||||
- if [ -n "${INSTALL_GCC6_FROM_PPA}" ]; then
|
||||
sudo add-apt-repository -y "ppa:ubuntu-toolchain-r/test";
|
||||
sudo apt-get update --option Acquire::Retries=100 --option Acquire::http::Timeout="60";
|
||||
fi
|
||||
|
||||
install:
|
||||
- if [ -n "${INSTALL_GCC6_FROM_PPA}" ]; then
|
||||
travis_wait sudo -E apt-get -yq --no-install-suggests --no-install-recommends install g++-6;
|
||||
fi
|
||||
- if [ "${TRAVIS_OS_NAME}" == "linux" -a "${BUILD_32_BITS}" == "OFF" ]; then
|
||||
travis_wait sudo -E apt-get -y --no-install-suggests --no-install-recommends install llvm-3.9-tools;
|
||||
sudo cp /usr/lib/llvm-3.9/bin/FileCheck /usr/local/bin/;
|
||||
fi
|
||||
- if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then
|
||||
PATH=~/.local/bin:${PATH};
|
||||
pip install --user --upgrade pip;
|
||||
travis_wait pip install --user cpp-coveralls;
|
||||
fi
|
||||
- if [ "${C_COMPILER}" == "gcc-7" -a "${TRAVIS_OS_NAME}" == "osx" ]; then
|
||||
rm -f /usr/local/include/c++;
|
||||
brew update;
|
||||
travis_wait brew install gcc@7;
|
||||
fi
|
||||
- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then
|
||||
sudo apt-get update -qq;
|
||||
sudo apt-get install -qq unzip cmake3;
|
||||
wget https://github.com/bazelbuild/bazel/releases/download/3.2.0/bazel-3.2.0-installer-linux-x86_64.sh --output-document bazel-installer.sh;
|
||||
travis_wait sudo bash bazel-installer.sh;
|
||||
fi
|
||||
- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
|
||||
curl -L -o bazel-installer.sh https://github.com/bazelbuild/bazel/releases/download/3.2.0/bazel-3.2.0-installer-darwin-x86_64.sh;
|
||||
travis_wait sudo bash bazel-installer.sh;
|
||||
fi
|
||||
|
||||
script:
|
||||
- cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_C_FLAGS="${EXTRA_FLAGS}" -DCMAKE_CXX_FLAGS="${EXTRA_FLAGS} ${EXTRA_CXX_FLAGS}" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON -DBENCHMARK_BUILD_32_BITS=${BUILD_32_BITS} ${EXTRA_OPTIONS} ..
|
||||
- make
|
||||
- ctest -C ${BUILD_TYPE} --output-on-failure
|
||||
- bazel test -c dbg --define google_benchmark.have_regex=posix --announce_rc --verbose_failures --test_output=errors --keep_going //test/...
|
||||
|
||||
after_success:
|
||||
- if [ "${BUILD_TYPE}" == "Coverage" -a "${TRAVIS_OS_NAME}" == "linux" ]; then
|
||||
coveralls --include src --include include --gcov-options '\-lp' --root .. --build-root .;
|
||||
fi
|
@ -1,115 +0,0 @@
|
||||
import os
|
||||
import ycm_core
|
||||
|
||||
# These are the compilation flags that will be used in case there's no
|
||||
# compilation database set (by default, one is not set).
|
||||
# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
|
||||
flags = [
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-pedantic-errors',
|
||||
'-std=c++0x',
|
||||
'-fno-strict-aliasing',
|
||||
'-O3',
|
||||
'-DNDEBUG',
|
||||
# ...and the same thing goes for the magic -x option which specifies the
|
||||
# language that the files to be compiled are written in. This is mostly
|
||||
# relevant for c++ headers.
|
||||
# For a C project, you would set this to 'c' instead of 'c++'.
|
||||
'-x', 'c++',
|
||||
'-I', 'include',
|
||||
'-isystem', '/usr/include',
|
||||
'-isystem', '/usr/local/include',
|
||||
]
|
||||
|
||||
|
||||
# Set this to the absolute path to the folder (NOT the file!) containing the
|
||||
# compile_commands.json file to use that instead of 'flags'. See here for
|
||||
# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
#
|
||||
# Most projects will NOT need to set this to anything; you can just change the
|
||||
# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
|
||||
compilation_database_folder = ''
|
||||
|
||||
if os.path.exists( compilation_database_folder ):
|
||||
database = ycm_core.CompilationDatabase( compilation_database_folder )
|
||||
else:
|
||||
database = None
|
||||
|
||||
SOURCE_EXTENSIONS = [ '.cc' ]
|
||||
|
||||
def DirectoryOfThisScript():
|
||||
return os.path.dirname( os.path.abspath( __file__ ) )
|
||||
|
||||
|
||||
def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
|
||||
if not working_directory:
|
||||
return list( flags )
|
||||
new_flags = []
|
||||
make_next_absolute = False
|
||||
path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
|
||||
for flag in flags:
|
||||
new_flag = flag
|
||||
|
||||
if make_next_absolute:
|
||||
make_next_absolute = False
|
||||
if not flag.startswith( '/' ):
|
||||
new_flag = os.path.join( working_directory, flag )
|
||||
|
||||
for path_flag in path_flags:
|
||||
if flag == path_flag:
|
||||
make_next_absolute = True
|
||||
break
|
||||
|
||||
if flag.startswith( path_flag ):
|
||||
path = flag[ len( path_flag ): ]
|
||||
new_flag = path_flag + os.path.join( working_directory, path )
|
||||
break
|
||||
|
||||
if new_flag:
|
||||
new_flags.append( new_flag )
|
||||
return new_flags
|
||||
|
||||
|
||||
def IsHeaderFile( filename ):
|
||||
extension = os.path.splitext( filename )[ 1 ]
|
||||
return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
|
||||
|
||||
|
||||
def GetCompilationInfoForFile( filename ):
|
||||
# The compilation_commands.json file generated by CMake does not have entries
|
||||
# for header files. So we do our best by asking the db for flags for a
|
||||
# corresponding source file, if any. If one exists, the flags for that file
|
||||
# should be good enough.
|
||||
if IsHeaderFile( filename ):
|
||||
basename = os.path.splitext( filename )[ 0 ]
|
||||
for extension in SOURCE_EXTENSIONS:
|
||||
replacement_file = basename + extension
|
||||
if os.path.exists( replacement_file ):
|
||||
compilation_info = database.GetCompilationInfoForFile(
|
||||
replacement_file )
|
||||
if compilation_info.compiler_flags_:
|
||||
return compilation_info
|
||||
return None
|
||||
return database.GetCompilationInfoForFile( filename )
|
||||
|
||||
|
||||
def FlagsForFile( filename, **kwargs ):
|
||||
if database:
|
||||
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
|
||||
# python list, but a "list-like" StringVec object
|
||||
compilation_info = GetCompilationInfoForFile( filename )
|
||||
if not compilation_info:
|
||||
return None
|
||||
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute(
|
||||
compilation_info.compiler_flags_,
|
||||
compilation_info.compiler_working_dir_ )
|
||||
else:
|
||||
relative_to = DirectoryOfThisScript()
|
||||
final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
|
||||
|
||||
return {
|
||||
'flags': final_flags,
|
||||
'do_cache': True
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
# This is the official list of benchmark authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS files.
|
||||
# See the latter for an explanation.
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Albert Pretorius <pretoalb@gmail.com>
|
||||
Alex Steele <steeleal123@gmail.com>
|
||||
Andriy Berestovskyy <berestovskyy@gmail.com>
|
||||
Arne Beer <arne@twobeer.de>
|
||||
Carto
|
||||
Christian Wassermann <christian_wassermann@web.de>
|
||||
Christopher Seymour <chris.j.seymour@hotmail.com>
|
||||
Colin Braley <braley.colin@gmail.com>
|
||||
Daniel Harvey <danielharvey458@gmail.com>
|
||||
David Coeurjolly <david.coeurjolly@liris.cnrs.fr>
|
||||
Deniz Evrenci <denizevrenci@gmail.com>
|
||||
Dirac Research
|
||||
Dominik Czarnota <dominik.b.czarnota@gmail.com>
|
||||
Eric Backus <eric_backus@alum.mit.edu>
|
||||
Eric Fiselier <eric@efcs.ca>
|
||||
Eugene Zhuk <eugene.zhuk@gmail.com>
|
||||
Evgeny Safronov <division494@gmail.com>
|
||||
Federico Ficarelli <federico.ficarelli@gmail.com>
|
||||
Felix Homann <linuxaudio@showlabor.de>
|
||||
Gergő Szitár <szitar.gergo@gmail.com>
|
||||
Google Inc.
|
||||
International Business Machines Corporation
|
||||
Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com>
|
||||
Jern-Kuan Leong <jernkuan@gmail.com>
|
||||
JianXiong Zhou <zhoujianxiong2@gmail.com>
|
||||
Joao Paulo Magalhaes <joaoppmagalhaes@gmail.com>
|
||||
Jordan Williams <jwillikers@protonmail.com>
|
||||
Jussi Knuuttila <jussi.knuuttila@gmail.com>
|
||||
Kaito Udagawa <umireon@gmail.com>
|
||||
Kishan Kumar <kumar.kishan@outlook.com>
|
||||
Lei Xu <eddyxu@gmail.com>
|
||||
Matt Clarkson <mattyclarkson@gmail.com>
|
||||
Maxim Vafin <maxvafin@gmail.com>
|
||||
MongoDB Inc.
|
||||
Nick Hutchinson <nshutchinson@gmail.com>
|
||||
Norman Heino <norman.heino@gmail.com>
|
||||
Oleksandr Sochka <sasha.sochka@gmail.com>
|
||||
Ori Livneh <ori.livneh@gmail.com>
|
||||
Paul Redmond <paul.redmond@gmail.com>
|
||||
Radoslav Yovchev <radoslav.tm@gmail.com>
|
||||
Roman Lebedev <lebedev.ri@gmail.com>
|
||||
Sayan Bhattacharjee <aero.sayan@gmail.com>
|
||||
Shuo Chen <chenshuo@chenshuo.com>
|
||||
Steinar H. Gunderson <sgunderson@bigfoot.com>
|
||||
Stripe, Inc.
|
||||
Tobias Schmidt <tobias.schmidt@in.tum.de>
|
||||
Yixuan Qiu <yixuanq@gmail.com>
|
||||
Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
Zbigniew Skowron <zbychs@gmail.com>
|
||||
Min-Yih Hsu <yihshyng223@gmail.com>
|
@ -1,44 +0,0 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
config_setting(
|
||||
name = "windows",
|
||||
values = {
|
||||
"cpu": "x64_windows",
|
||||
},
|
||||
visibility = [":__subpackages__"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "benchmark",
|
||||
srcs = glob(
|
||||
[
|
||||
"src/*.cc",
|
||||
"src/*.h",
|
||||
],
|
||||
exclude = ["src/benchmark_main.cc"],
|
||||
),
|
||||
hdrs = ["include/benchmark/benchmark.h"],
|
||||
linkopts = select({
|
||||
":windows": ["-DEFAULTLIB:shlwapi.lib"],
|
||||
"//conditions:default": ["-pthread"],
|
||||
}),
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "benchmark_main",
|
||||
srcs = ["src/benchmark_main.cc"],
|
||||
hdrs = ["include/benchmark/benchmark.h"],
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":benchmark"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "benchmark_internal_headers",
|
||||
hdrs = glob(["src/*.h"]),
|
||||
visibility = ["//test:__pkg__"],
|
||||
)
|
@ -1,313 +0,0 @@
|
||||
cmake_minimum_required (VERSION 3.5.1)
|
||||
|
||||
foreach(p
|
||||
CMP0048 # OK to clear PROJECT_VERSION on project()
|
||||
CMP0054 # CMake 3.1
|
||||
CMP0056 # export EXE_LINKER_FLAGS to try_run
|
||||
CMP0057 # Support no if() IN_LIST operator
|
||||
CMP0063 # Honor visibility properties for all targets
|
||||
CMP0077 # Allow option() overrides in importing projects
|
||||
)
|
||||
if(POLICY ${p})
|
||||
cmake_policy(SET ${p} NEW)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
project (benchmark VERSION 1.5.4 LANGUAGES CXX)
|
||||
|
||||
option(BENCHMARK_ENABLE_TESTING "Enable testing of the benchmark library." ON)
|
||||
option(BENCHMARK_ENABLE_EXCEPTIONS "Enable the use of exceptions in the benchmark library." ON)
|
||||
option(BENCHMARK_ENABLE_LTO "Enable link time optimisation of the benchmark library." OFF)
|
||||
option(BENCHMARK_USE_LIBCXX "Build and test using libc++ as the standard library." OFF)
|
||||
if(NOT MSVC)
|
||||
option(BENCHMARK_BUILD_32_BITS "Build a 32 bit version of the library." OFF)
|
||||
else()
|
||||
set(BENCHMARK_BUILD_32_BITS OFF CACHE BOOL "Build a 32 bit version of the library - unsupported when using MSVC)" FORCE)
|
||||
endif()
|
||||
option(BENCHMARK_ENABLE_INSTALL "Enable installation of benchmark. (Projects embedding benchmark may want to turn this OFF.)" ON)
|
||||
|
||||
# Allow unmet dependencies to be met using CMake's ExternalProject mechanics, which
|
||||
# may require downloading the source code.
|
||||
option(BENCHMARK_DOWNLOAD_DEPENDENCIES "Allow the downloading and in-tree building of unmet dependencies" OFF)
|
||||
|
||||
# This option can be used to disable building and running unit tests which depend on gtest
|
||||
# in cases where it is not possible to build or find a valid version of gtest.
|
||||
option(BENCHMARK_ENABLE_GTEST_TESTS "Enable building the unit tests which depend on gtest" ON)
|
||||
|
||||
option(BENCHMARK_ENABLE_LIBPFM "Enable performance counters provided by libpfm" OFF)
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
if(MSVC)
|
||||
# As of CMake 3.18, CMAKE_SYSTEM_PROCESSOR is not set properly for MSVC and
|
||||
# cross-compilation (e.g. Host=x86_64, target=aarch64) requires using the
|
||||
# undocumented, but working variable.
|
||||
# See https://gitlab.kitware.com/cmake/cmake/-/issues/15170
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${MSVC_CXX_ARCHITECTURE_ID})
|
||||
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "ARM")
|
||||
set(CMAKE_CROSSCOMPILING TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(ENABLE_ASSEMBLY_TESTS_DEFAULT OFF)
|
||||
function(should_enable_assembly_tests)
|
||||
if(CMAKE_BUILD_TYPE)
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
|
||||
if (${CMAKE_BUILD_TYPE_LOWER} MATCHES "coverage")
|
||||
# FIXME: The --coverage flag needs to be removed when building assembly
|
||||
# tests for this to work.
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
if (MSVC)
|
||||
return()
|
||||
elseif(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
return()
|
||||
elseif(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# FIXME: Make these work on 32 bit builds
|
||||
return()
|
||||
elseif(BENCHMARK_BUILD_32_BITS)
|
||||
# FIXME: Make these work on 32 bit builds
|
||||
return()
|
||||
endif()
|
||||
find_program(LLVM_FILECHECK_EXE FileCheck)
|
||||
if (LLVM_FILECHECK_EXE)
|
||||
set(LLVM_FILECHECK_EXE "${LLVM_FILECHECK_EXE}" CACHE PATH "llvm filecheck" FORCE)
|
||||
message(STATUS "LLVM FileCheck Found: ${LLVM_FILECHECK_EXE}")
|
||||
else()
|
||||
message(STATUS "Failed to find LLVM FileCheck")
|
||||
return()
|
||||
endif()
|
||||
set(ENABLE_ASSEMBLY_TESTS_DEFAULT ON PARENT_SCOPE)
|
||||
endfunction()
|
||||
should_enable_assembly_tests()
|
||||
|
||||
# This option disables the building and running of the assembly verification tests
|
||||
option(BENCHMARK_ENABLE_ASSEMBLY_TESTS "Enable building and running the assembly tests"
|
||||
${ENABLE_ASSEMBLY_TESTS_DEFAULT})
|
||||
|
||||
# Make sure we can import out CMake functions
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
|
||||
# Read the git tags to determine the project version
|
||||
include(GetGitVersion)
|
||||
get_git_version(GIT_VERSION)
|
||||
|
||||
# If no git version can be determined, use the version
|
||||
# from the project() command
|
||||
if ("${GIT_VERSION}" STREQUAL "0.0.0")
|
||||
set(VERSION "${benchmark_VERSION}")
|
||||
else()
|
||||
set(VERSION "${GIT_VERSION}")
|
||||
endif()
|
||||
# Tell the user what versions we are using
|
||||
message(STATUS "Version: ${VERSION}")
|
||||
|
||||
# The version of the libraries
|
||||
set(GENERIC_LIB_VERSION ${VERSION})
|
||||
string(SUBSTRING ${VERSION} 0 1 GENERIC_LIB_SOVERSION)
|
||||
|
||||
# Import our CMake modules
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(AddCXXCompilerFlag)
|
||||
include(CXXFeatureCheck)
|
||||
|
||||
if (BENCHMARK_BUILD_32_BITS)
|
||||
add_required_cxx_compiler_flag(-m32)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
# Turn compiler warnings up to 11
|
||||
string(REGEX REPLACE "[-/]W[1-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
if (NOT BENCHMARK_ENABLE_EXCEPTIONS)
|
||||
add_cxx_compiler_flag(-EHs-)
|
||||
add_cxx_compiler_flag(-EHa-)
|
||||
add_definitions(-D_HAS_EXCEPTIONS=0)
|
||||
endif()
|
||||
# Link time optimisation
|
||||
if (BENCHMARK_ENABLE_LTO)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GL")
|
||||
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
|
||||
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
|
||||
string(REGEX REPLACE "[-/]INCREMENTAL" "/INCREMENTAL:NO" CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /GL")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL "${CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL} /LTCG")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL} /LTCG")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} /LTCG")
|
||||
endif()
|
||||
else()
|
||||
# Try and enable C++11. Don't use C++14 because it doesn't work in some
|
||||
# configurations.
|
||||
add_cxx_compiler_flag(-std=c++11)
|
||||
if (NOT HAVE_CXX_FLAG_STD_CXX11)
|
||||
add_cxx_compiler_flag(-std=c++0x)
|
||||
endif()
|
||||
|
||||
# Turn compiler warnings up to 11
|
||||
add_cxx_compiler_flag(-Wall)
|
||||
add_cxx_compiler_flag(-Wextra)
|
||||
add_cxx_compiler_flag(-Wshadow)
|
||||
add_cxx_compiler_flag(-Werror RELEASE)
|
||||
add_cxx_compiler_flag(-Werror RELWITHDEBINFO)
|
||||
add_cxx_compiler_flag(-Werror MINSIZEREL)
|
||||
if (NOT BENCHMARK_ENABLE_TESTING)
|
||||
# Disable warning when compiling tests as gtest does not use 'override'.
|
||||
add_cxx_compiler_flag(-Wsuggest-override)
|
||||
endif()
|
||||
add_cxx_compiler_flag(-pedantic)
|
||||
add_cxx_compiler_flag(-pedantic-errors)
|
||||
add_cxx_compiler_flag(-Wshorten-64-to-32)
|
||||
add_cxx_compiler_flag(-fstrict-aliasing)
|
||||
# Disable warnings regarding deprecated parts of the library while building
|
||||
# and testing those parts of the library.
|
||||
add_cxx_compiler_flag(-Wno-deprecated-declarations)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
# Intel silently ignores '-Wno-deprecated-declarations',
|
||||
# warning no. 1786 must be explicitly disabled.
|
||||
# See #631 for rationale.
|
||||
add_cxx_compiler_flag(-wd1786)
|
||||
endif()
|
||||
# Disable deprecation warnings for release builds (when -Werror is enabled).
|
||||
add_cxx_compiler_flag(-Wno-deprecated RELEASE)
|
||||
add_cxx_compiler_flag(-Wno-deprecated RELWITHDEBINFO)
|
||||
add_cxx_compiler_flag(-Wno-deprecated MINSIZEREL)
|
||||
if (NOT BENCHMARK_ENABLE_EXCEPTIONS)
|
||||
add_cxx_compiler_flag(-fno-exceptions)
|
||||
endif()
|
||||
|
||||
if (HAVE_CXX_FLAG_FSTRICT_ALIASING)
|
||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") #ICC17u2: Many false positives for Wstrict-aliasing
|
||||
add_cxx_compiler_flag(-Wstrict-aliasing)
|
||||
endif()
|
||||
endif()
|
||||
# ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially overridden
|
||||
# (because of deprecated overload)
|
||||
add_cxx_compiler_flag(-wd654)
|
||||
add_cxx_compiler_flag(-Wthread-safety)
|
||||
if (HAVE_CXX_FLAG_WTHREAD_SAFETY)
|
||||
cxx_feature_check(THREAD_SAFETY_ATTRIBUTES)
|
||||
endif()
|
||||
|
||||
# On most UNIX like platforms g++ and clang++ define _GNU_SOURCE as a
|
||||
# predefined macro, which turns on all of the wonderful libc extensions.
|
||||
# However g++ doesn't do this in Cygwin so we have to define it ourselfs
|
||||
# since we depend on GNU/POSIX/BSD extensions.
|
||||
if (CYGWIN)
|
||||
add_definitions(-D_GNU_SOURCE=1)
|
||||
endif()
|
||||
|
||||
if (QNXNTO)
|
||||
add_definitions(-D_QNX_SOURCE)
|
||||
endif()
|
||||
|
||||
# Link time optimisation
|
||||
if (BENCHMARK_ENABLE_LTO)
|
||||
add_cxx_compiler_flag(-flto)
|
||||
add_cxx_compiler_flag(-Wno-lto-type-mismatch)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
find_program(GCC_AR gcc-ar)
|
||||
if (GCC_AR)
|
||||
set(CMAKE_AR ${GCC_AR})
|
||||
endif()
|
||||
find_program(GCC_RANLIB gcc-ranlib)
|
||||
if (GCC_RANLIB)
|
||||
set(CMAKE_RANLIB ${GCC_RANLIB})
|
||||
endif()
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
include(llvm-toolchain)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Coverage build type
|
||||
set(BENCHMARK_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG}"
|
||||
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
||||
FORCE)
|
||||
set(BENCHMARK_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_DEBUG}"
|
||||
CACHE STRING "Flags used for linking binaries during coverage builds."
|
||||
FORCE)
|
||||
set(BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}"
|
||||
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
||||
FORCE)
|
||||
mark_as_advanced(
|
||||
BENCHMARK_CXX_FLAGS_COVERAGE
|
||||
BENCHMARK_EXE_LINKER_FLAGS_COVERAGE
|
||||
BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE)
|
||||
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.")
|
||||
add_cxx_compiler_flag(--coverage COVERAGE)
|
||||
endif()
|
||||
|
||||
if (BENCHMARK_USE_LIBCXX)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
add_cxx_compiler_flag(-stdlib=libc++)
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR
|
||||
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
add_cxx_compiler_flag(-nostdinc++)
|
||||
message(WARNING "libc++ header path must be manually specified using CMAKE_CXX_FLAGS")
|
||||
# Adding -nodefaultlibs directly to CMAKE_<TYPE>_LINKER_FLAGS will break
|
||||
# configuration checks such as 'find_package(Threads)'
|
||||
list(APPEND BENCHMARK_CXX_LINKER_FLAGS -nodefaultlibs)
|
||||
# -lc++ cannot be added directly to CMAKE_<TYPE>_LINKER_FLAGS because
|
||||
# linker flags appear before all linker inputs and -lc++ must appear after.
|
||||
list(APPEND BENCHMARK_CXX_LIBRARIES c++)
|
||||
else()
|
||||
message(FATAL_ERROR "-DBENCHMARK_USE_LIBCXX:BOOL=ON is not supported for compiler")
|
||||
endif()
|
||||
endif(BENCHMARK_USE_LIBCXX)
|
||||
|
||||
set(EXTRA_CXX_FLAGS "")
|
||||
if (WIN32 AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
# Clang on Windows fails to compile the regex feature check under C++11
|
||||
set(EXTRA_CXX_FLAGS "-DCMAKE_CXX_STANDARD=14")
|
||||
endif()
|
||||
|
||||
# C++ feature checks
|
||||
# Determine the correct regular expression engine to use
|
||||
cxx_feature_check(STD_REGEX ${EXTRA_CXX_FLAGS})
|
||||
cxx_feature_check(GNU_POSIX_REGEX ${EXTRA_CXX_FLAGS})
|
||||
cxx_feature_check(POSIX_REGEX ${EXTRA_CXX_FLAGS})
|
||||
if(NOT HAVE_STD_REGEX AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX)
|
||||
message(FATAL_ERROR "Failed to determine the source files for the regular expression backend")
|
||||
endif()
|
||||
if (NOT BENCHMARK_ENABLE_EXCEPTIONS AND HAVE_STD_REGEX
|
||||
AND NOT HAVE_GNU_POSIX_REGEX AND NOT HAVE_POSIX_REGEX)
|
||||
message(WARNING "Using std::regex with exceptions disabled is not fully supported")
|
||||
endif()
|
||||
|
||||
cxx_feature_check(STEADY_CLOCK)
|
||||
# Ensure we have pthreads
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if (BENCHMARK_ENABLE_LIBPFM)
|
||||
find_package(PFM)
|
||||
endif()
|
||||
|
||||
# Set up directories
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
|
||||
# Build the targets
|
||||
add_subdirectory(src)
|
||||
|
||||
if (BENCHMARK_ENABLE_TESTING)
|
||||
enable_testing()
|
||||
if (BENCHMARK_ENABLE_GTEST_TESTS AND
|
||||
NOT (TARGET gtest AND TARGET gtest_main AND
|
||||
TARGET gmock AND TARGET gmock_main))
|
||||
include(GoogleTest)
|
||||
endif()
|
||||
add_subdirectory(test)
|
||||
endif()
|
@ -1,58 +0,0 @@
|
||||
# How to contribute #
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
a just a few small guidelines you need to follow.
|
||||
|
||||
|
||||
## Contributor License Agreement ##
|
||||
|
||||
Contributions to any Google project must be accompanied by a Contributor
|
||||
License Agreement. This is not a copyright **assignment**, it simply gives
|
||||
Google permission to use and redistribute your contributions as part of the
|
||||
project.
|
||||
|
||||
* If you are an individual writing original source code and you're sure you
|
||||
own the intellectual property, then you'll need to sign an [individual
|
||||
CLA][].
|
||||
|
||||
* If you work for a company that wants to allow you to contribute your work,
|
||||
then you'll need to sign a [corporate CLA][].
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted
|
||||
one (even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
[individual CLA]: https://developers.google.com/open-source/cla/individual
|
||||
[corporate CLA]: https://developers.google.com/open-source/cla/corporate
|
||||
|
||||
Once your CLA is submitted (or if you already submitted one for
|
||||
another Google project), make a commit adding yourself to the
|
||||
[AUTHORS][] and [CONTRIBUTORS][] files. This commit can be part
|
||||
of your first [pull request][].
|
||||
|
||||
[AUTHORS]: AUTHORS
|
||||
[CONTRIBUTORS]: CONTRIBUTORS
|
||||
|
||||
|
||||
## Submitting a patch ##
|
||||
|
||||
1. It's generally best to start by opening a new issue describing the bug or
|
||||
feature you're intending to fix. Even if you think it's relatively minor,
|
||||
it's helpful to know what people are working on. Mention in the initial
|
||||
issue that you are planning to work on that bug or feature so that it can
|
||||
be assigned to you.
|
||||
|
||||
1. Follow the normal process of [forking][] the project, and setup a new
|
||||
branch to work in. It's important that each group of changes be done in
|
||||
separate branches in order to ensure that a pull request only includes the
|
||||
commits related to that bug or feature.
|
||||
|
||||
1. Do your best to have [well-formed commit messages][] for each change.
|
||||
This provides consistency throughout the project, and ensures that commit
|
||||
messages are able to be formatted properly by various git tools.
|
||||
|
||||
1. Finally, push the commits to your fork and submit a [pull request][].
|
||||
|
||||
[forking]: https://help.github.com/articles/fork-a-repo
|
||||
[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
||||
[pull request]: https://help.github.com/articles/creating-a-pull-request
|
@ -1,85 +0,0 @@
|
||||
# People who have agreed to one of the CLAs and can contribute patches.
|
||||
# The AUTHORS file lists the copyright holders; this file
|
||||
# lists people. For example, Google employees are listed here
|
||||
# but not in AUTHORS, because Google holds the copyright.
|
||||
#
|
||||
# Names should be added to this file only after verifying that
|
||||
# the individual or the individual's organization has agreed to
|
||||
# the appropriate Contributor License Agreement, found here:
|
||||
#
|
||||
# https://developers.google.com/open-source/cla/individual
|
||||
# https://developers.google.com/open-source/cla/corporate
|
||||
#
|
||||
# The agreement for individuals can be filled out on the web.
|
||||
#
|
||||
# When adding J Random Contributor's name to this file,
|
||||
# either J's name or J's organization's name should be
|
||||
# added to the AUTHORS file, depending on whether the
|
||||
# individual or corporate CLA was used.
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name <email address>
|
||||
#
|
||||
# Please keep the list sorted.
|
||||
|
||||
Abhina Sreeskantharajan <abhina.sreeskantharajan@ibm.com>
|
||||
Albert Pretorius <pretoalb@gmail.com>
|
||||
Alex Steele <steelal123@gmail.com>
|
||||
Andriy Berestovskyy <berestovskyy@gmail.com>
|
||||
Arne Beer <arne@twobeer.de>
|
||||
Billy Robert O'Neal III <billy.oneal@gmail.com> <bion@microsoft.com>
|
||||
Chris Kennelly <ckennelly@google.com> <ckennelly@ckennelly.com>
|
||||
Christian Wassermann <christian_wassermann@web.de>
|
||||
Christopher Seymour <chris.j.seymour@hotmail.com>
|
||||
Colin Braley <braley.colin@gmail.com>
|
||||
Cyrille Faucheux <cyrille.faucheux@gmail.com>
|
||||
Daniel Harvey <danielharvey458@gmail.com>
|
||||
David Coeurjolly <david.coeurjolly@liris.cnrs.fr>
|
||||
Deniz Evrenci <denizevrenci@gmail.com>
|
||||
Dominic Hamon <dma@stripysock.com> <dominic@google.com>
|
||||
Dominik Czarnota <dominik.b.czarnota@gmail.com>
|
||||
Eric Backus <eric_backus@alum.mit.edu>
|
||||
Eric Fiselier <eric@efcs.ca>
|
||||
Eugene Zhuk <eugene.zhuk@gmail.com>
|
||||
Evgeny Safronov <division494@gmail.com>
|
||||
Fanbo Meng <fanbo.meng@ibm.com>
|
||||
Federico Ficarelli <federico.ficarelli@gmail.com>
|
||||
Felix Homann <linuxaudio@showlabor.de>
|
||||
Geoffrey Martin-Noble <gcmn@google.com> <gmngeoffrey@gmail.com>
|
||||
Gergő Szitár <szitar.gergo@gmail.com>
|
||||
Hannes Hauswedell <h2@fsfe.org>
|
||||
Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com>
|
||||
Jern-Kuan Leong <jernkuan@gmail.com>
|
||||
JianXiong Zhou <zhoujianxiong2@gmail.com>
|
||||
Joao Paulo Magalhaes <joaoppmagalhaes@gmail.com>
|
||||
John Millikin <jmillikin@stripe.com>
|
||||
Jordan Williams <jwillikers@protonmail.com>
|
||||
Jussi Knuuttila <jussi.knuuttila@gmail.com>
|
||||
Kai Wolf <kai.wolf@gmail.com>
|
||||
Kaito Udagawa <umireon@gmail.com>
|
||||
Kishan Kumar <kumar.kishan@outlook.com>
|
||||
Lei Xu <eddyxu@gmail.com>
|
||||
Matt Clarkson <mattyclarkson@gmail.com>
|
||||
Maxim Vafin <maxvafin@gmail.com>
|
||||
Nick Hutchinson <nshutchinson@gmail.com>
|
||||
Norman Heino <norman.heino@gmail.com>
|
||||
Oleksandr Sochka <sasha.sochka@gmail.com>
|
||||
Ori Livneh <ori.livneh@gmail.com>
|
||||
Pascal Leroy <phl@google.com>
|
||||
Paul Redmond <paul.redmond@gmail.com>
|
||||
Pierre Phaneuf <pphaneuf@google.com>
|
||||
Radoslav Yovchev <radoslav.tm@gmail.com>
|
||||
Raul Marin <rmrodriguez@cartodb.com>
|
||||
Ray Glover <ray.glover@uk.ibm.com>
|
||||
Robert Guo <robert.guo@mongodb.com>
|
||||
Roman Lebedev <lebedev.ri@gmail.com>
|
||||
Sayan Bhattacharjee <aero.sayan@gmail.com>
|
||||
Shuo Chen <chenshuo@chenshuo.com>
|
||||
Steven Wan <wan.yu@ibm.com>
|
||||
Tobias Schmidt <tobias.schmidt@in.tum.de>
|
||||
Tobias Ulvgård <tobias.ulvgard@dirac.se>
|
||||
Tom Madams <tom.ej.madams@gmail.com> <tmadams@google.com>
|
||||
Yixuan Qiu <yixuanq@gmail.com>
|
||||
Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
Zbigniew Skowron <zbychs@gmail.com>
|
||||
Min-Yih Hsu <yihshyng223@gmail.com>
|
@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
workspace(name = "com_github_google_benchmark")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "rules_cc",
|
||||
strip_prefix = "rules_cc-a508235df92e71d537fcbae0c7c952ea6957a912",
|
||||
urls = ["https://github.com/bazelbuild/rules_cc/archive/a508235df92e71d537fcbae0c7c952ea6957a912.zip"],
|
||||
sha256 = "d7dc12c1d5bc1a87474de8e3d17b7731a4dcebcfb8aa3990fe8ac7734ef12f2f",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "com_google_absl",
|
||||
sha256 = "f41868f7a938605c92936230081175d1eae87f6ea2c248f41077c8f88316f111",
|
||||
strip_prefix = "abseil-cpp-20200225.2",
|
||||
urls = ["https://github.com/abseil/abseil-cpp/archive/20200225.2.tar.gz"],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
strip_prefix = "googletest-3f0cf6b62ad1eb50d8736538363d3580dd640c3e",
|
||||
urls = ["https://github.com/google/googletest/archive/3f0cf6b62ad1eb50d8736538363d3580dd640c3e.zip"],
|
||||
sha256 = "8f827dd550db8b4fdf73904690df0be9fccc161017c9038a724bc9a0617a1bc8",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "pybind11",
|
||||
build_file = "@//bindings/python:pybind11.BUILD",
|
||||
sha256 = "1eed57bc6863190e35637290f97a20c81cfe4d9090ac0a24f3bbf08f265eb71d",
|
||||
strip_prefix = "pybind11-2.4.3",
|
||||
urls = ["https://github.com/pybind/pybind11/archive/v2.4.3.tar.gz"],
|
||||
)
|
||||
|
||||
new_local_repository(
|
||||
name = "python_headers",
|
||||
build_file = "@//bindings/python:python_headers.BUILD",
|
||||
path = "/usr/include/python3.6", # May be overwritten by setup.py.
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "rules_python",
|
||||
url = "https://github.com/bazelbuild/rules_python/releases/download/0.1.0/rules_python-0.1.0.tar.gz",
|
||||
sha256 = "b6d46438523a3ec0f3cead544190ee13223a52f6a6765a29eae7b7cc24cc83a0",
|
||||
)
|
||||
|
||||
load("@rules_python//python:pip.bzl", pip3_install="pip_install")
|
||||
|
||||
pip3_install(
|
||||
name = "py_deps",
|
||||
requirements = "//:requirements.txt",
|
||||
)
|
@ -1,2 +0,0 @@
|
||||
theme: jekyll-theme-midnight
|
||||
markdown: GFM
|
@ -1,50 +0,0 @@
|
||||
version: '{build}'
|
||||
|
||||
image: Visual Studio 2017
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- compiler: msvc-15-seh
|
||||
generator: "Visual Studio 15 2017"
|
||||
|
||||
- compiler: msvc-15-seh
|
||||
generator: "Visual Studio 15 2017 Win64"
|
||||
|
||||
- compiler: msvc-14-seh
|
||||
generator: "Visual Studio 14 2015"
|
||||
|
||||
- compiler: msvc-14-seh
|
||||
generator: "Visual Studio 14 2015 Win64"
|
||||
|
||||
- compiler: gcc-5.3.0-posix
|
||||
generator: "MinGW Makefiles"
|
||||
cxx_path: 'C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin'
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
install:
|
||||
# git bash conflicts with MinGW makefiles
|
||||
- if "%generator%"=="MinGW Makefiles" (set "PATH=%PATH:C:\Program Files\Git\usr\bin;=%")
|
||||
- if not "%cxx_path%"=="" (set "PATH=%PATH%;%cxx_path%")
|
||||
|
||||
build_script:
|
||||
- md _build -Force
|
||||
- cd _build
|
||||
- echo %configuration%
|
||||
- cmake -G "%generator%" "-DCMAKE_BUILD_TYPE=%configuration%" -DBENCHMARK_DOWNLOAD_DEPENDENCIES=ON ..
|
||||
- cmake --build . --config %configuration%
|
||||
|
||||
test_script:
|
||||
- ctest --build-config %configuration% --timeout 300 --output-on-failure
|
||||
|
||||
artifacts:
|
||||
- path: '_build/CMakeFiles/*.log'
|
||||
name: logs
|
||||
- path: '_build/Testing/**/*.xml'
|
||||
name: test_results
|
@ -1,3 +0,0 @@
|
||||
exports_files(glob(["*.BUILD"]))
|
||||
exports_files(["build_defs.bzl"])
|
||||
|
@ -1,25 +0,0 @@
|
||||
_SHARED_LIB_SUFFIX = {
|
||||
"//conditions:default": ".so",
|
||||
"//:windows": ".dll",
|
||||
}
|
||||
|
||||
def py_extension(name, srcs, hdrs = [], copts = [], features = [], deps = []):
|
||||
for shared_lib_suffix in _SHARED_LIB_SUFFIX.values():
|
||||
shared_lib_name = name + shared_lib_suffix
|
||||
native.cc_binary(
|
||||
name = shared_lib_name,
|
||||
linkshared = 1,
|
||||
linkstatic = 1,
|
||||
srcs = srcs + hdrs,
|
||||
copts = copts,
|
||||
features = features,
|
||||
deps = deps,
|
||||
)
|
||||
|
||||
return native.py_library(
|
||||
name = name,
|
||||
data = select({
|
||||
platform: [name + shared_lib_suffix]
|
||||
for platform, shared_lib_suffix in _SHARED_LIB_SUFFIX.items()
|
||||
}),
|
||||
)
|
@ -1,38 +0,0 @@
|
||||
load("//bindings/python:build_defs.bzl", "py_extension")
|
||||
|
||||
py_library(
|
||||
name = "google_benchmark",
|
||||
srcs = ["__init__.py"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":_benchmark",
|
||||
# pip; absl:app
|
||||
],
|
||||
)
|
||||
|
||||
py_extension(
|
||||
name = "_benchmark",
|
||||
srcs = ["benchmark.cc"],
|
||||
copts = [
|
||||
"-fexceptions",
|
||||
"-fno-strict-aliasing",
|
||||
],
|
||||
features = ["-use_header_modules"],
|
||||
deps = [
|
||||
"//:benchmark",
|
||||
"@pybind11",
|
||||
"@python_headers",
|
||||
],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "example",
|
||||
srcs = ["example.py"],
|
||||
python_version = "PY3",
|
||||
srcs_version = "PY3",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":google_benchmark",
|
||||
],
|
||||
)
|
||||
|
@ -1,158 +0,0 @@
|
||||
# Copyright 2020 Google Inc. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
"""Python benchmarking utilities.
|
||||
|
||||
Example usage:
|
||||
import google_benchmark as benchmark
|
||||
|
||||
@benchmark.register
|
||||
def my_benchmark(state):
|
||||
... # Code executed outside `while` loop is not timed.
|
||||
|
||||
while state:
|
||||
... # Code executed within `while` loop is timed.
|
||||
|
||||
if __name__ == '__main__':
|
||||
benchmark.main()
|
||||
"""
|
||||
|
||||
from absl import app
|
||||
from google_benchmark import _benchmark
|
||||
from google_benchmark._benchmark import (
|
||||
Counter,
|
||||
kNanosecond,
|
||||
kMicrosecond,
|
||||
kMillisecond,
|
||||
kSecond,
|
||||
oNone,
|
||||
o1,
|
||||
oN,
|
||||
oNSquared,
|
||||
oNCubed,
|
||||
oLogN,
|
||||
oNLogN,
|
||||
oAuto,
|
||||
oLambda,
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"register",
|
||||
"main",
|
||||
"Counter",
|
||||
"kNanosecond",
|
||||
"kMicrosecond",
|
||||
"kMillisecond",
|
||||
"kSecond",
|
||||
"oNone",
|
||||
"o1",
|
||||
"oN",
|
||||
"oNSquared",
|
||||
"oNCubed",
|
||||
"oLogN",
|
||||
"oNLogN",
|
||||
"oAuto",
|
||||
"oLambda",
|
||||
]
|
||||
|
||||
__version__ = "0.2.0"
|
||||
|
||||
|
||||
class __OptionMaker:
|
||||
"""A stateless class to collect benchmark options.
|
||||
|
||||
Collect all decorator calls like @option.range(start=0, limit=1<<5).
|
||||
"""
|
||||
|
||||
class Options:
|
||||
"""Pure data class to store options calls, along with the benchmarked function."""
|
||||
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
self.builder_calls = []
|
||||
|
||||
@classmethod
|
||||
def make(cls, func_or_options):
|
||||
"""Make Options from Options or the benchmarked function."""
|
||||
if isinstance(func_or_options, cls.Options):
|
||||
return func_or_options
|
||||
return cls.Options(func_or_options)
|
||||
|
||||
def __getattr__(self, builder_name):
|
||||
"""Append option call in the Options."""
|
||||
|
||||
# The function that get returned on @option.range(start=0, limit=1<<5).
|
||||
def __builder_method(*args, **kwargs):
|
||||
|
||||
# The decorator that get called, either with the benchmared function
|
||||
# or the previous Options
|
||||
def __decorator(func_or_options):
|
||||
options = self.make(func_or_options)
|
||||
options.builder_calls.append((builder_name, args, kwargs))
|
||||
# The decorator returns Options so it is not technically a decorator
|
||||
# and needs a final call to @regiser
|
||||
return options
|
||||
|
||||
return __decorator
|
||||
|
||||
return __builder_method
|
||||
|
||||
|
||||
# Alias for nicer API.
|
||||
# We have to instantiate an object, even if stateless, to be able to use __getattr__
|
||||
# on option.range
|
||||
option = __OptionMaker()
|
||||
|
||||
|
||||
def register(undefined=None, *, name=None):
|
||||
"""Register function for benchmarking."""
|
||||
if undefined is None:
|
||||
# Decorator is called without parenthesis so we return a decorator
|
||||
return lambda f: register(f, name=name)
|
||||
|
||||
# We have either the function to benchmark (simple case) or an instance of Options
|
||||
# (@option._ case).
|
||||
options = __OptionMaker.make(undefined)
|
||||
|
||||
if name is None:
|
||||
name = options.func.__name__
|
||||
|
||||
# We register the benchmark and reproduce all the @option._ calls onto the
|
||||
# benchmark builder pattern
|
||||
benchmark = _benchmark.RegisterBenchmark(name, options.func)
|
||||
for name, args, kwargs in options.builder_calls[::-1]:
|
||||
getattr(benchmark, name)(*args, **kwargs)
|
||||
|
||||
# return the benchmarked function because the decorator does not modify it
|
||||
return options.func
|
||||
|
||||
|
||||
def _flags_parser(argv):
|
||||
argv = _benchmark.Initialize(argv)
|
||||
return app.parse_flags_with_usage(argv)
|
||||
|
||||
|
||||
def _run_benchmarks(argv):
|
||||
if len(argv) > 1:
|
||||
raise app.UsageError("Too many command-line arguments.")
|
||||
return _benchmark.RunSpecifiedBenchmarks()
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
return app.run(_run_benchmarks, argv=argv, flags_parser=_flags_parser)
|
||||
|
||||
|
||||
# Methods for use with custom main function.
|
||||
initialize = _benchmark.Initialize
|
||||
run_benchmarks = _benchmark.RunSpecifiedBenchmarks
|
@ -1,181 +0,0 @@
|
||||
// Benchmark for Python.
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "pybind11/operators.h"
|
||||
#include "pybind11/pybind11.h"
|
||||
#include "pybind11/stl.h"
|
||||
#include "pybind11/stl_bind.h"
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
PYBIND11_MAKE_OPAQUE(benchmark::UserCounters);
|
||||
|
||||
namespace {
|
||||
namespace py = ::pybind11;
|
||||
|
||||
std::vector<std::string> Initialize(const std::vector<std::string>& argv) {
|
||||
// The `argv` pointers here become invalid when this function returns, but
|
||||
// benchmark holds the pointer to `argv[0]`. We create a static copy of it
|
||||
// so it persists, and replace the pointer below.
|
||||
static std::string executable_name(argv[0]);
|
||||
std::vector<char*> ptrs;
|
||||
ptrs.reserve(argv.size());
|
||||
for (auto& arg : argv) {
|
||||
ptrs.push_back(const_cast<char*>(arg.c_str()));
|
||||
}
|
||||
ptrs[0] = const_cast<char*>(executable_name.c_str());
|
||||
int argc = static_cast<int>(argv.size());
|
||||
benchmark::Initialize(&argc, ptrs.data());
|
||||
std::vector<std::string> remaining_argv;
|
||||
remaining_argv.reserve(argc);
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
remaining_argv.emplace_back(ptrs[i]);
|
||||
}
|
||||
return remaining_argv;
|
||||
}
|
||||
|
||||
benchmark::internal::Benchmark* RegisterBenchmark(const char* name,
|
||||
py::function f) {
|
||||
return benchmark::RegisterBenchmark(
|
||||
name, [f](benchmark::State& state) { f(&state); });
|
||||
}
|
||||
|
||||
PYBIND11_MODULE(_benchmark, m) {
|
||||
using benchmark::TimeUnit;
|
||||
py::enum_<TimeUnit>(m, "TimeUnit")
|
||||
.value("kNanosecond", TimeUnit::kNanosecond)
|
||||
.value("kMicrosecond", TimeUnit::kMicrosecond)
|
||||
.value("kMillisecond", TimeUnit::kMillisecond)
|
||||
.value("kSecond", TimeUnit::kSecond)
|
||||
.export_values();
|
||||
|
||||
using benchmark::BigO;
|
||||
py::enum_<BigO>(m, "BigO")
|
||||
.value("oNone", BigO::oNone)
|
||||
.value("o1", BigO::o1)
|
||||
.value("oN", BigO::oN)
|
||||
.value("oNSquared", BigO::oNSquared)
|
||||
.value("oNCubed", BigO::oNCubed)
|
||||
.value("oLogN", BigO::oLogN)
|
||||
.value("oNLogN", BigO::oLogN)
|
||||
.value("oAuto", BigO::oAuto)
|
||||
.value("oLambda", BigO::oLambda)
|
||||
.export_values();
|
||||
|
||||
using benchmark::internal::Benchmark;
|
||||
py::class_<Benchmark>(m, "Benchmark")
|
||||
// For methods returning a pointer tor the current object, reference
|
||||
// return policy is used to ask pybind not to take ownership oof the
|
||||
// returned object and avoid calling delete on it.
|
||||
// https://pybind11.readthedocs.io/en/stable/advanced/functions.html#return-value-policies
|
||||
//
|
||||
// For methods taking a const std::vector<...>&, a copy is created
|
||||
// because a it is bound to a Python list.
|
||||
// https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
|
||||
.def("unit", &Benchmark::Unit, py::return_value_policy::reference)
|
||||
.def("arg", &Benchmark::Arg, py::return_value_policy::reference)
|
||||
.def("args", &Benchmark::Args, py::return_value_policy::reference)
|
||||
.def("range", &Benchmark::Range, py::return_value_policy::reference,
|
||||
py::arg("start"), py::arg("limit"))
|
||||
.def("dense_range", &Benchmark::DenseRange,
|
||||
py::return_value_policy::reference, py::arg("start"),
|
||||
py::arg("limit"), py::arg("step") = 1)
|
||||
.def("ranges", &Benchmark::Ranges, py::return_value_policy::reference)
|
||||
.def("args_product", &Benchmark::ArgsProduct,
|
||||
py::return_value_policy::reference)
|
||||
.def("arg_name", &Benchmark::ArgName, py::return_value_policy::reference)
|
||||
.def("arg_names", &Benchmark::ArgNames,
|
||||
py::return_value_policy::reference)
|
||||
.def("range_pair", &Benchmark::RangePair,
|
||||
py::return_value_policy::reference, py::arg("lo1"), py::arg("hi1"),
|
||||
py::arg("lo2"), py::arg("hi2"))
|
||||
.def("range_multiplier", &Benchmark::RangeMultiplier,
|
||||
py::return_value_policy::reference)
|
||||
.def("min_time", &Benchmark::MinTime, py::return_value_policy::reference)
|
||||
.def("iterations", &Benchmark::Iterations,
|
||||
py::return_value_policy::reference)
|
||||
.def("repetitions", &Benchmark::Repetitions,
|
||||
py::return_value_policy::reference)
|
||||
.def("report_aggregates_only", &Benchmark::ReportAggregatesOnly,
|
||||
py::return_value_policy::reference, py::arg("value") = true)
|
||||
.def("display_aggregates_only", &Benchmark::DisplayAggregatesOnly,
|
||||
py::return_value_policy::reference, py::arg("value") = true)
|
||||
.def("measure_process_cpu_time", &Benchmark::MeasureProcessCPUTime,
|
||||
py::return_value_policy::reference)
|
||||
.def("use_real_time", &Benchmark::UseRealTime,
|
||||
py::return_value_policy::reference)
|
||||
.def("use_manual_time", &Benchmark::UseManualTime,
|
||||
py::return_value_policy::reference)
|
||||
.def(
|
||||
"complexity",
|
||||
(Benchmark * (Benchmark::*)(benchmark::BigO)) & Benchmark::Complexity,
|
||||
py::return_value_policy::reference,
|
||||
py::arg("complexity") = benchmark::oAuto);
|
||||
|
||||
using benchmark::Counter;
|
||||
py::class_<Counter> py_counter(m, "Counter");
|
||||
|
||||
py::enum_<Counter::Flags>(py_counter, "Flags")
|
||||
.value("kDefaults", Counter::Flags::kDefaults)
|
||||
.value("kIsRate", Counter::Flags::kIsRate)
|
||||
.value("kAvgThreads", Counter::Flags::kAvgThreads)
|
||||
.value("kAvgThreadsRate", Counter::Flags::kAvgThreadsRate)
|
||||
.value("kIsIterationInvariant", Counter::Flags::kIsIterationInvariant)
|
||||
.value("kIsIterationInvariantRate",
|
||||
Counter::Flags::kIsIterationInvariantRate)
|
||||
.value("kAvgIterations", Counter::Flags::kAvgIterations)
|
||||
.value("kAvgIterationsRate", Counter::Flags::kAvgIterationsRate)
|
||||
.value("kInvert", Counter::Flags::kInvert)
|
||||
.export_values()
|
||||
.def(py::self | py::self);
|
||||
|
||||
py::enum_<Counter::OneK>(py_counter, "OneK")
|
||||
.value("kIs1000", Counter::OneK::kIs1000)
|
||||
.value("kIs1024", Counter::OneK::kIs1024)
|
||||
.export_values();
|
||||
|
||||
py_counter
|
||||
.def(py::init<double, Counter::Flags, Counter::OneK>(),
|
||||
py::arg("value") = 0., py::arg("flags") = Counter::kDefaults,
|
||||
py::arg("k") = Counter::kIs1000)
|
||||
.def(py::init([](double value) { return Counter(value); }))
|
||||
.def_readwrite("value", &Counter::value)
|
||||
.def_readwrite("flags", &Counter::flags)
|
||||
.def_readwrite("oneK", &Counter::oneK);
|
||||
py::implicitly_convertible<py::float_, Counter>();
|
||||
py::implicitly_convertible<py::int_, Counter>();
|
||||
|
||||
py::bind_map<benchmark::UserCounters>(m, "UserCounters");
|
||||
|
||||
using benchmark::State;
|
||||
py::class_<State>(m, "State")
|
||||
.def("__bool__", &State::KeepRunning)
|
||||
.def_property_readonly("keep_running", &State::KeepRunning)
|
||||
.def("pause_timing", &State::PauseTiming)
|
||||
.def("resume_timing", &State::ResumeTiming)
|
||||
.def("skip_with_error", &State::SkipWithError)
|
||||
.def_property_readonly("error_occurred", &State::error_occurred)
|
||||
.def("set_iteration_time", &State::SetIterationTime)
|
||||
.def_property("bytes_processed", &State::bytes_processed,
|
||||
&State::SetBytesProcessed)
|
||||
.def_property("complexity_n", &State::complexity_length_n,
|
||||
&State::SetComplexityN)
|
||||
.def_property("items_processed", &State::items_processed,
|
||||
&State::SetItemsProcessed)
|
||||
.def("set_label", (void (State::*)(const char*)) & State::SetLabel)
|
||||
.def("range", &State::range, py::arg("pos") = 0)
|
||||
.def_property_readonly("iterations", &State::iterations)
|
||||
.def_readwrite("counters", &State::counters)
|
||||
.def_readonly("thread_index", &State::thread_index)
|
||||
.def_readonly("threads", &State::threads);
|
||||
|
||||
m.def("Initialize", Initialize);
|
||||
m.def("RegisterBenchmark", RegisterBenchmark,
|
||||
py::return_value_policy::reference);
|
||||
m.def("RunSpecifiedBenchmarks",
|
||||
[]() { benchmark::RunSpecifiedBenchmarks(); });
|
||||
};
|
||||
} // namespace
|
@ -1,136 +0,0 @@
|
||||
# Copyright 2020 Google Inc. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
"""Example of Python using C++ benchmark framework.
|
||||
|
||||
To run this example, you must first install the `google_benchmark` Python package.
|
||||
|
||||
To install using `setup.py`, download and extract the `google_benchmark` source.
|
||||
In the extracted directory, execute:
|
||||
python setup.py install
|
||||
"""
|
||||
|
||||
import random
|
||||
import time
|
||||
|
||||
import google_benchmark as benchmark
|
||||
from google_benchmark import Counter
|
||||
|
||||
|
||||
@benchmark.register
|
||||
def empty(state):
|
||||
while state:
|
||||
pass
|
||||
|
||||
|
||||
@benchmark.register
|
||||
def sum_million(state):
|
||||
while state:
|
||||
sum(range(1_000_000))
|
||||
|
||||
@benchmark.register
|
||||
def pause_timing(state):
|
||||
"""Pause timing every iteration."""
|
||||
while state:
|
||||
# Construct a list of random ints every iteration without timing it
|
||||
state.pause_timing()
|
||||
random_list = [random.randint(0, 100) for _ in range(100)]
|
||||
state.resume_timing()
|
||||
# Time the in place sorting algorithm
|
||||
random_list.sort()
|
||||
|
||||
|
||||
@benchmark.register
|
||||
def skipped(state):
|
||||
if True: # Test some predicate here.
|
||||
state.skip_with_error("some error")
|
||||
return # NOTE: You must explicitly return, or benchmark will continue.
|
||||
|
||||
... # Benchmark code would be here.
|
||||
|
||||
|
||||
@benchmark.register
|
||||
def manual_timing(state):
|
||||
while state:
|
||||
# Manually count Python CPU time
|
||||
start = time.perf_counter() # perf_counter_ns() in Python 3.7+
|
||||
# Something to benchmark
|
||||
time.sleep(0.01)
|
||||
end = time.perf_counter()
|
||||
state.set_iteration_time(end - start)
|
||||
|
||||
|
||||
@benchmark.register
|
||||
def custom_counters(state):
|
||||
"""Collect cutom metric using benchmark.Counter."""
|
||||
num_foo = 0.0
|
||||
while state:
|
||||
# Benchmark some code here
|
||||
pass
|
||||
# Collect some custom metric named foo
|
||||
num_foo += 0.13
|
||||
|
||||
# Automatic Counter from numbers.
|
||||
state.counters["foo"] = num_foo
|
||||
# Set a counter as a rate.
|
||||
state.counters["foo_rate"] = Counter(num_foo, Counter.kIsRate)
|
||||
# Set a counter as an inverse of rate.
|
||||
state.counters["foo_inv_rate"] = Counter(num_foo, Counter.kIsRate | Counter.kInvert)
|
||||
# Set a counter as a thread-average quantity.
|
||||
state.counters["foo_avg"] = Counter(num_foo, Counter.kAvgThreads)
|
||||
# There's also a combined flag:
|
||||
state.counters["foo_avg_rate"] = Counter(num_foo, Counter.kAvgThreadsRate)
|
||||
|
||||
|
||||
@benchmark.register
|
||||
@benchmark.option.measure_process_cpu_time()
|
||||
@benchmark.option.use_real_time()
|
||||
def with_options(state):
|
||||
while state:
|
||||
sum(range(1_000_000))
|
||||
|
||||
|
||||
@benchmark.register(name="sum_million_microseconds")
|
||||
@benchmark.option.unit(benchmark.kMicrosecond)
|
||||
def with_options(state):
|
||||
while state:
|
||||
sum(range(1_000_000))
|
||||
|
||||
|
||||
@benchmark.register
|
||||
@benchmark.option.arg(100)
|
||||
@benchmark.option.arg(1000)
|
||||
def passing_argument(state):
|
||||
while state:
|
||||
sum(range(state.range(0)))
|
||||
|
||||
|
||||
@benchmark.register
|
||||
@benchmark.option.range(8, limit=8 << 10)
|
||||
def using_range(state):
|
||||
while state:
|
||||
sum(range(state.range(0)))
|
||||
|
||||
|
||||
@benchmark.register
|
||||
@benchmark.option.range_multiplier(2)
|
||||
@benchmark.option.range(1 << 10, 1 << 18)
|
||||
@benchmark.option.complexity(benchmark.oN)
|
||||
def computing_complexity(state):
|
||||
while state:
|
||||
sum(range(state.range(0)))
|
||||
state.complexity_n = state.range(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
benchmark.main()
|
@ -1,20 +0,0 @@
|
||||
cc_library(
|
||||
name = "pybind11",
|
||||
hdrs = glob(
|
||||
include = [
|
||||
"include/pybind11/*.h",
|
||||
"include/pybind11/detail/*.h",
|
||||
],
|
||||
exclude = [
|
||||
"include/pybind11/common.h",
|
||||
"include/pybind11/eigen.h",
|
||||
],
|
||||
),
|
||||
copts = [
|
||||
"-fexceptions",
|
||||
"-Wno-undefined-inline",
|
||||
"-Wno-pragma-once-outside-header",
|
||||
],
|
||||
includes = ["include"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
@ -1,6 +0,0 @@
|
||||
cc_library(
|
||||
name = "python_headers",
|
||||
hdrs = glob(["**/*.h"]),
|
||||
includes = ["."],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
@ -1,2 +0,0 @@
|
||||
absl-py>=0.7.1
|
||||
|
@ -1,78 +0,0 @@
|
||||
# - Adds a compiler flag if it is supported by the compiler
|
||||
#
|
||||
# This function checks that the supplied compiler flag is supported and then
|
||||
# adds it to the corresponding compiler flags
|
||||
#
|
||||
# add_cxx_compiler_flag(<FLAG> [<VARIANT>])
|
||||
#
|
||||
# - Example
|
||||
#
|
||||
# include(AddCXXCompilerFlag)
|
||||
# add_cxx_compiler_flag(-Wall)
|
||||
# add_cxx_compiler_flag(-no-strict-aliasing RELEASE)
|
||||
# Requires CMake 2.6+
|
||||
|
||||
if(__add_cxx_compiler_flag)
|
||||
return()
|
||||
endif()
|
||||
set(__add_cxx_compiler_flag INCLUDED)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
function(mangle_compiler_flag FLAG OUTPUT)
|
||||
string(TOUPPER "HAVE_CXX_FLAG_${FLAG}" SANITIZED_FLAG)
|
||||
string(REPLACE "+" "X" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
string(REGEX REPLACE "_+" "_" SANITIZED_FLAG ${SANITIZED_FLAG})
|
||||
set(${OUTPUT} "${SANITIZED_FLAG}" PARENT_SCOPE)
|
||||
endfunction(mangle_compiler_flag)
|
||||
|
||||
function(add_cxx_compiler_flag FLAG)
|
||||
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
|
||||
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
if(${MANGLED_FLAG})
|
||||
if(ARGC GREATER 1)
|
||||
set(VARIANT ${ARGV1})
|
||||
string(TOUPPER "_${VARIANT}" VARIANT)
|
||||
else()
|
||||
set(VARIANT "")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${BENCHMARK_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(add_required_cxx_compiler_flag FLAG)
|
||||
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}")
|
||||
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
if(${MANGLED_FLAG})
|
||||
if(ARGC GREATER 1)
|
||||
set(VARIANT ${ARGV1})
|
||||
string(TOUPPER "_${VARIANT}" VARIANT)
|
||||
else()
|
||||
set(VARIANT "")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}" PARENT_SCOPE)
|
||||
else()
|
||||
message(FATAL_ERROR "Required flag '${FLAG}' is not supported by the compiler")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(check_cxx_warning_flag FLAG)
|
||||
mangle_compiler_flag("${FLAG}" MANGLED_FLAG)
|
||||
set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
|
||||
# Add -Werror to ensure the compiler generates an error if the warning flag
|
||||
# doesn't exist.
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror ${FLAG}")
|
||||
check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG})
|
||||
set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}")
|
||||
endfunction()
|
@ -1,69 +0,0 @@
|
||||
# - Compile and run code to check for C++ features
|
||||
#
|
||||
# This functions compiles a source file under the `cmake` folder
|
||||
# and adds the corresponding `HAVE_[FILENAME]` flag to the CMake
|
||||
# environment
|
||||
#
|
||||
# cxx_feature_check(<FLAG> [<VARIANT>])
|
||||
#
|
||||
# - Example
|
||||
#
|
||||
# include(CXXFeatureCheck)
|
||||
# cxx_feature_check(STD_REGEX)
|
||||
# Requires CMake 2.8.12+
|
||||
|
||||
if(__cxx_feature_check)
|
||||
return()
|
||||
endif()
|
||||
set(__cxx_feature_check INCLUDED)
|
||||
|
||||
function(cxx_feature_check FILE)
|
||||
string(TOLOWER ${FILE} FILE)
|
||||
string(TOUPPER ${FILE} VAR)
|
||||
string(TOUPPER "HAVE_${VAR}" FEATURE)
|
||||
if (DEFINED HAVE_${VAR})
|
||||
set(HAVE_${VAR} 1 PARENT_SCOPE)
|
||||
add_definitions(-DHAVE_${VAR})
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (ARGC GREATER 1)
|
||||
message(STATUS "Enabling additional flags: ${ARGV1}")
|
||||
list(APPEND BENCHMARK_CXX_LINKER_FLAGS ${ARGV1})
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED COMPILE_${FEATURE})
|
||||
message(STATUS "Performing Test ${FEATURE}")
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
try_compile(COMPILE_${FEATURE}
|
||||
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp
|
||||
CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}
|
||||
LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES})
|
||||
if(COMPILE_${FEATURE})
|
||||
message(WARNING
|
||||
"If you see build failures due to cross compilation, try setting HAVE_${VAR} to 0")
|
||||
set(RUN_${FEATURE} 0 CACHE INTERNAL "")
|
||||
else()
|
||||
set(RUN_${FEATURE} 1 CACHE INTERNAL "")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Performing Test ${FEATURE}")
|
||||
try_run(RUN_${FEATURE} COMPILE_${FEATURE}
|
||||
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${FILE}.cpp
|
||||
CMAKE_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS}
|
||||
LINK_LIBRARIES ${BENCHMARK_CXX_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(RUN_${FEATURE} EQUAL 0)
|
||||
message(STATUS "Performing Test ${FEATURE} -- success")
|
||||
set(HAVE_${VAR} 1 PARENT_SCOPE)
|
||||
add_definitions(-DHAVE_${VAR})
|
||||
else()
|
||||
if(NOT COMPILE_${FEATURE})
|
||||
message(STATUS "Performing Test ${FEATURE} -- failed to compile")
|
||||
else()
|
||||
message(STATUS "Performing Test ${FEATURE} -- compiled but failed to run")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
@ -1 +0,0 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake")
|
@ -1,58 +0,0 @@
|
||||
# - Returns a version string from Git tags
|
||||
#
|
||||
# This function inspects the annotated git tags for the project and returns a string
|
||||
# into a CMake variable
|
||||
#
|
||||
# get_git_version(<var>)
|
||||
#
|
||||
# - Example
|
||||
#
|
||||
# include(GetGitVersion)
|
||||
# get_git_version(GIT_VERSION)
|
||||
#
|
||||
# Requires CMake 2.8.11+
|
||||
find_package(Git)
|
||||
|
||||
if(__get_git_version)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_version INCLUDED)
|
||||
|
||||
function(get_git_version var)
|
||||
if(GIT_EXECUTABLE)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
RESULT_VARIABLE status
|
||||
OUTPUT_VARIABLE GIT_DESCRIBE_VERSION
|
||||
ERROR_QUIET)
|
||||
if(status)
|
||||
set(GIT_DESCRIBE_VERSION "v0.0.0")
|
||||
endif()
|
||||
|
||||
string(STRIP ${GIT_DESCRIBE_VERSION} GIT_DESCRIBE_VERSION)
|
||||
if(GIT_DESCRIBE_VERSION MATCHES v[^-]*-)
|
||||
string(REGEX REPLACE "v([^-]*)-([0-9]+)-.*" "\\1.\\2" GIT_VERSION ${GIT_DESCRIBE_VERSION})
|
||||
else()
|
||||
string(REGEX REPLACE "v(.*)" "\\1" GIT_VERSION ${GIT_DESCRIBE_VERSION})
|
||||
endif()
|
||||
|
||||
# Work out if the repository is dirty
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_QUIET
|
||||
ERROR_QUIET)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD --
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_DIFF_INDEX
|
||||
ERROR_QUIET)
|
||||
string(COMPARE NOTEQUAL "${GIT_DIFF_INDEX}" "" GIT_DIRTY)
|
||||
if (${GIT_DIRTY})
|
||||
set(GIT_DESCRIBE_VERSION "${GIT_DESCRIBE_VERSION}-dirty")
|
||||
endif()
|
||||
message(STATUS "git version: ${GIT_DESCRIBE_VERSION} normalized to ${GIT_VERSION}")
|
||||
else()
|
||||
set(GIT_VERSION "0.0.0")
|
||||
endif()
|
||||
|
||||
set(${var} ${GIT_VERSION} PARENT_SCOPE)
|
||||
endfunction()
|
@ -1,41 +0,0 @@
|
||||
# Download and unpack googletest at configure time
|
||||
set(GOOGLETEST_PREFIX "${benchmark_BINARY_DIR}/third_party/googletest")
|
||||
configure_file(${benchmark_SOURCE_DIR}/cmake/GoogleTest.cmake.in ${GOOGLETEST_PREFIX}/CMakeLists.txt @ONLY)
|
||||
|
||||
set(GOOGLETEST_PATH "${CMAKE_CURRENT_SOURCE_DIR}/googletest" CACHE PATH "") # Mind the quotes
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
|
||||
-DALLOW_DOWNLOADING_GOOGLETEST=${BENCHMARK_DOWNLOAD_DEPENDENCIES} -DGOOGLETEST_PATH:PATH=${GOOGLETEST_PATH} .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${GOOGLETEST_PREFIX}
|
||||
)
|
||||
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${GOOGLETEST_PREFIX}
|
||||
)
|
||||
|
||||
if(result)
|
||||
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
# Prevent overriding the parent project's compiler/linker
|
||||
# settings on Windows
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
include(${GOOGLETEST_PREFIX}/googletest-paths.cmake)
|
||||
|
||||
# Add googletest directly to our build. This defines
|
||||
# the gtest and gtest_main targets.
|
||||
add_subdirectory(${GOOGLETEST_SOURCE_DIR}
|
||||
${GOOGLETEST_BINARY_DIR}
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
set_target_properties(gtest PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:gtest,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
set_target_properties(gtest_main PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:gtest_main,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
set_target_properties(gmock PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:gmock,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
set_target_properties(gmock_main PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:gmock_main,INTERFACE_INCLUDE_DIRECTORIES>)
|
@ -1,58 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
project(googletest-download NONE)
|
||||
|
||||
# Enable ExternalProject CMake module
|
||||
include(ExternalProject)
|
||||
|
||||
option(ALLOW_DOWNLOADING_GOOGLETEST "If googletest src tree is not found in location specified by GOOGLETEST_PATH, do fetch the archive from internet" OFF)
|
||||
set(GOOGLETEST_PATH "/usr/src/googletest" CACHE PATH
|
||||
"Path to the googletest root tree. Should contain googletest and googlemock subdirs. And CMakeLists.txt in root, and in both of these subdirs")
|
||||
|
||||
# Download and install GoogleTest
|
||||
|
||||
message(STATUS "Looking for Google Test sources")
|
||||
message(STATUS "Looking for Google Test sources in ${GOOGLETEST_PATH}")
|
||||
if(EXISTS "${GOOGLETEST_PATH}" AND IS_DIRECTORY "${GOOGLETEST_PATH}" AND EXISTS "${GOOGLETEST_PATH}/CMakeLists.txt" AND
|
||||
EXISTS "${GOOGLETEST_PATH}/googletest" AND IS_DIRECTORY "${GOOGLETEST_PATH}/googletest" AND EXISTS "${GOOGLETEST_PATH}/googletest/CMakeLists.txt" AND
|
||||
EXISTS "${GOOGLETEST_PATH}/googlemock" AND IS_DIRECTORY "${GOOGLETEST_PATH}/googlemock" AND EXISTS "${GOOGLETEST_PATH}/googlemock/CMakeLists.txt")
|
||||
message(STATUS "Found Google Test in ${GOOGLETEST_PATH}")
|
||||
|
||||
ExternalProject_Add(
|
||||
googletest
|
||||
PREFIX "${CMAKE_BINARY_DIR}"
|
||||
DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/download"
|
||||
SOURCE_DIR "${GOOGLETEST_PATH}" # use existing src dir.
|
||||
BINARY_DIR "${CMAKE_BINARY_DIR}/build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
else()
|
||||
if(NOT ALLOW_DOWNLOADING_GOOGLETEST)
|
||||
message(SEND_ERROR "Did not find Google Test sources! Either pass correct path in GOOGLETEST_PATH, or enable BENCHMARK_DOWNLOAD_DEPENDENCIES, or disable BENCHMARK_ENABLE_GTEST_TESTS / BENCHMARK_ENABLE_TESTING.")
|
||||
else()
|
||||
message(WARNING "Did not find Google Test sources! Fetching from web...")
|
||||
ExternalProject_Add(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG master
|
||||
PREFIX "${CMAKE_BINARY_DIR}"
|
||||
STAMP_DIR "${CMAKE_BINARY_DIR}/stamp"
|
||||
DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/download"
|
||||
SOURCE_DIR "${CMAKE_BINARY_DIR}/src"
|
||||
BINARY_DIR "${CMAKE_BINARY_DIR}/build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
ExternalProject_Get_Property(googletest SOURCE_DIR BINARY_DIR)
|
||||
file(WRITE googletest-paths.cmake
|
||||
"set(GOOGLETEST_SOURCE_DIR \"${SOURCE_DIR}\")
|
||||
set(GOOGLETEST_BINARY_DIR \"${BINARY_DIR}\")
|
||||
")
|
@ -1,12 +0,0 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
|
||||
Name: @PROJECT_NAME@
|
||||
Description: Google microbenchmark framework
|
||||
Version: @VERSION@
|
||||
|
||||
Libs: -L${libdir} -lbenchmark
|
||||
Libs.private: -lpthread
|
||||
Cflags: -I${includedir}
|
@ -1,12 +0,0 @@
|
||||
#include <gnuregex.h>
|
||||
#include <string>
|
||||
int main() {
|
||||
std::string str = "test0159";
|
||||
regex_t re;
|
||||
int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB);
|
||||
if (ec != 0) {
|
||||
return ec;
|
||||
}
|
||||
return regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0;
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
find_package(LLVMAr REQUIRED)
|
||||
set(CMAKE_AR "${LLVMAR_EXECUTABLE}" CACHE FILEPATH "" FORCE)
|
||||
|
||||
find_package(LLVMNm REQUIRED)
|
||||
set(CMAKE_NM "${LLVMNM_EXECUTABLE}" CACHE FILEPATH "" FORCE)
|
||||
|
||||
find_package(LLVMRanLib REQUIRED)
|
||||
set(CMAKE_RANLIB "${LLVMRANLIB_EXECUTABLE}" CACHE FILEPATH "" FORCE)
|
@ -1,14 +0,0 @@
|
||||
#include <regex.h>
|
||||
#include <string>
|
||||
int main() {
|
||||
std::string str = "test0159";
|
||||
regex_t re;
|
||||
int ec = regcomp(&re, "^[a-z]+[0-9]+$", REG_EXTENDED | REG_NOSUB);
|
||||
if (ec != 0) {
|
||||
return ec;
|
||||
}
|
||||
int ret = regexec(&re, str.c_str(), 0, nullptr, 0) ? -1 : 0;
|
||||
regfree(&re);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
macro(split_list listname)
|
||||
string(REPLACE ";" " " ${listname} "${${listname}}")
|
||||
endmacro()
|
@ -1,10 +0,0 @@
|
||||
#include <regex>
|
||||
#include <string>
|
||||
int main() {
|
||||
const std::string str = "test0159";
|
||||
std::regex re;
|
||||
re = std::regex("^[a-z]+[0-9]+$",
|
||||
std::regex_constants::extended | std::regex_constants::nosubs);
|
||||
return std::regex_search(str, re) ? 0 : -1;
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
#include <chrono>
|
||||
|
||||
int main() {
|
||||
typedef std::chrono::steady_clock Clock;
|
||||
Clock::time_point tp = Clock::now();
|
||||
((void)tp);
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#define HAVE_THREAD_SAFETY_ATTRIBUTES
|
||||
#include "../src/mutex.h"
|
||||
|
||||
int main() {}
|
@ -1,18 +0,0 @@
|
||||
# Build tool dependency policy
|
||||
|
||||
To ensure the broadest compatibility when building the benchmark library, but
|
||||
still allow forward progress, we require any build tooling to be available for:
|
||||
|
||||
* Debian stable AND
|
||||
* The last two Ubuntu LTS releases AND
|
||||
|
||||
Currently, this means using build tool versions that are available for Ubuntu
|
||||
16.04 (Xenial), Ubuntu 18.04 (Bionic), and Debian stretch.
|
||||
|
||||
_Note, [travis](.travis.yml) runs under Ubuntu 14.04 (Trusty) for linux builds._
|
||||
|
||||
## cmake
|
||||
The current supported version is cmake 3.5.1 as of 2018-06-06.
|
||||
|
||||
_Note, this version is also available for Ubuntu 14.04, the previous Ubuntu LTS
|
||||
release, as `cmake3`._
|
@ -1,147 +0,0 @@
|
||||
# Assembly Tests
|
||||
|
||||
The Benchmark library provides a number of functions whose primary
|
||||
purpose in to affect assembly generation, including `DoNotOptimize`
|
||||
and `ClobberMemory`. In addition there are other functions,
|
||||
such as `KeepRunning`, for which generating good assembly is paramount.
|
||||
|
||||
For these functions it's important to have tests that verify the
|
||||
correctness and quality of the implementation. This requires testing
|
||||
the code generated by the compiler.
|
||||
|
||||
This document describes how the Benchmark library tests compiler output,
|
||||
as well as how to properly write new tests.
|
||||
|
||||
|
||||
## Anatomy of a Test
|
||||
|
||||
Writing a test has two steps:
|
||||
|
||||
* Write the code you want to generate assembly for.
|
||||
* Add `// CHECK` lines to match against the verified assembly.
|
||||
|
||||
Example:
|
||||
```c++
|
||||
|
||||
// CHECK-LABEL: test_add:
|
||||
extern "C" int test_add() {
|
||||
extern int ExternInt;
|
||||
return ExternInt + 1;
|
||||
|
||||
// CHECK: movl ExternInt(%rip), %eax
|
||||
// CHECK: addl %eax
|
||||
// CHECK: ret
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### LLVM Filecheck
|
||||
|
||||
[LLVM's Filecheck](https://llvm.org/docs/CommandGuide/FileCheck.html)
|
||||
is used to test the generated assembly against the `// CHECK` lines
|
||||
specified in the tests source file. Please see the documentation
|
||||
linked above for information on how to write `CHECK` directives.
|
||||
|
||||
#### Tips and Tricks:
|
||||
|
||||
* Tests should match the minimal amount of output required to establish
|
||||
correctness. `CHECK` directives don't have to match on the exact next line
|
||||
after the previous match, so tests should omit checks for unimportant
|
||||
bits of assembly. ([`CHECK-NEXT`](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-next-directive)
|
||||
can be used to ensure a match occurs exactly after the previous match).
|
||||
|
||||
* The tests are compiled with `-O3 -g0`. So we're only testing the
|
||||
optimized output.
|
||||
|
||||
* The assembly output is further cleaned up using `tools/strip_asm.py`.
|
||||
This removes comments, assembler directives, and unused labels before
|
||||
the test is run.
|
||||
|
||||
* The generated and stripped assembly file for a test is output under
|
||||
`<build-directory>/test/<test-name>.s`
|
||||
|
||||
* Filecheck supports using [`CHECK` prefixes](https://llvm.org/docs/CommandGuide/FileCheck.html#cmdoption-check-prefixes)
|
||||
to specify lines that should only match in certain situations.
|
||||
The Benchmark tests use `CHECK-CLANG` and `CHECK-GNU` for lines that
|
||||
are only expected to match Clang or GCC's output respectively. Normal
|
||||
`CHECK` lines match against all compilers. (Note: `CHECK-NOT` and
|
||||
`CHECK-LABEL` are NOT prefixes. They are versions of non-prefixed
|
||||
`CHECK` lines)
|
||||
|
||||
* Use `extern "C"` to disable name mangling for specific functions. This
|
||||
makes them easier to name in the `CHECK` lines.
|
||||
|
||||
|
||||
## Problems Writing Portable Tests
|
||||
|
||||
Writing tests which check the code generated by a compiler are
|
||||
inherently non-portable. Different compilers and even different compiler
|
||||
versions may generate entirely different code. The Benchmark tests
|
||||
must tolerate this.
|
||||
|
||||
LLVM Filecheck provides a number of mechanisms to help write
|
||||
"more portable" tests; including [matching using regular expressions](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-pattern-matching-syntax),
|
||||
allowing the creation of [named variables](https://llvm.org/docs/CommandGuide/FileCheck.html#filecheck-variables)
|
||||
for later matching, and [checking non-sequential matches](https://llvm.org/docs/CommandGuide/FileCheck.html#the-check-dag-directive).
|
||||
|
||||
#### Capturing Variables
|
||||
|
||||
For example, say GCC stores a variable in a register but Clang stores
|
||||
it in memory. To write a test that tolerates both cases we "capture"
|
||||
the destination of the store, and then use the captured expression
|
||||
to write the remainder of the test.
|
||||
|
||||
```c++
|
||||
// CHECK-LABEL: test_div_no_op_into_shr:
|
||||
extern "C" void test_div_no_op_into_shr(int value) {
|
||||
int divisor = 2;
|
||||
benchmark::DoNotOptimize(divisor); // hide the value from the optimizer
|
||||
return value / divisor;
|
||||
|
||||
// CHECK: movl $2, [[DEST:.*]]
|
||||
// CHECK: idivl [[DEST]]
|
||||
// CHECK: ret
|
||||
}
|
||||
```
|
||||
|
||||
#### Using Regular Expressions to Match Differing Output
|
||||
|
||||
Often tests require testing assembly lines which may subtly differ
|
||||
between compilers or compiler versions. A common example of this
|
||||
is matching stack frame addresses. In this case regular expressions
|
||||
can be used to match the differing bits of output. For example:
|
||||
|
||||
```c++
|
||||
int ExternInt;
|
||||
struct Point { int x, y, z; };
|
||||
|
||||
// CHECK-LABEL: test_store_point:
|
||||
extern "C" void test_store_point() {
|
||||
Point p{ExternInt, ExternInt, ExternInt};
|
||||
benchmark::DoNotOptimize(p);
|
||||
|
||||
// CHECK: movl ExternInt(%rip), %eax
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
||||
// CHECK: movl %eax, -{{[0-9]+}}(%rsp)
|
||||
// CHECK: ret
|
||||
}
|
||||
```
|
||||
|
||||
## Current Requirements and Limitations
|
||||
|
||||
The tests require Filecheck to be installed along the `PATH` of the
|
||||
build machine. Otherwise the tests will be disabled.
|
||||
|
||||
Additionally, as mentioned in the previous section, codegen tests are
|
||||
inherently non-portable. Currently the tests are limited to:
|
||||
|
||||
* x86_64 targets.
|
||||
* Compiled with GCC or Clang
|
||||
|
||||
Further work could be done, at least on a limited basis, to extend the
|
||||
tests to other architectures and compilers (using `CHECK` prefixes).
|
||||
|
||||
Furthermore, the tests fail for builds which specify additional flags
|
||||
that modify code generation, including `--coverage` or `-fsanitize=`.
|
||||
|
@ -1 +0,0 @@
|
||||
theme: jekyll-theme-hacker
|
@ -1,34 +0,0 @@
|
||||
<a name="perf-counters" />
|
||||
|
||||
# User-Requested Performance Counters
|
||||
|
||||
When running benchmarks, the user may choose to request collection of
|
||||
performance counters. This may be useful in investigation scenarios - narrowing
|
||||
down the cause of a regression; or verifying that the underlying cause of a
|
||||
performance improvement matches expectations.
|
||||
|
||||
This feature is available if:
|
||||
|
||||
* The benchmark is run on an architecture featuring a Performance Monitoring
|
||||
Unit (PMU),
|
||||
* The benchmark is compiled with support for collecting counters. Currently,
|
||||
this requires [libpfm](http://perfmon2.sourceforge.net/) be available at build
|
||||
time
|
||||
|
||||
The feature does not require modifying benchmark code. Counter collection is
|
||||
handled at the boundaries where timer collection is also handled.
|
||||
|
||||
To opt-in:
|
||||
|
||||
* Install `libpfm4-dev`, e.g. `apt-get install libpfm4-dev`.
|
||||
* Enable the cmake flag BENCHMARK_ENABLE_LIBPFM.
|
||||
|
||||
To use, pass a comma-separated list of counter names through the
|
||||
`--benchmark_perf_counters` flag. The names are decoded through libpfm - meaning,
|
||||
they are platform specific, but some (e.g. `CYCLES` or `INSTRUCTIONS`) are
|
||||
mapped by libpfm to platform-specifics - see libpfm
|
||||
[documentation](http://perfmon2.sourceforge.net/docs.html) for more details.
|
||||
|
||||
The counter values are reported back through the [User Counters](../README.md#custom-counters)
|
||||
mechanism, meaning, they are available in all the formats (e.g. JSON) supported
|
||||
by User Counters.
|
@ -1,13 +0,0 @@
|
||||
<a name="interleaving" />
|
||||
|
||||
# Random Interleaving
|
||||
|
||||
[Random Interleaving](https://github.com/google/benchmark/issues/1051) is a
|
||||
technique to lower run-to-run variance. It randomly interleaves repetitions of a
|
||||
microbenchmark with repetitions from other microbenchmarks in the same benchmark
|
||||
test. Data shows it is able to lower run-to-run variance by
|
||||
[40%](https://github.com/google/benchmark/issues/1051) on average.
|
||||
|
||||
To use, you mainly need to set `--benchmark_enable_random_interleaving=true`,
|
||||
and optionally specify non-zero repetition count `--benchmark_repetitions=9`
|
||||
and optionally decrease the per-repetition time `--benchmark_min_time=0.1`.
|
@ -1,22 +0,0 @@
|
||||
# How to release
|
||||
|
||||
* Make sure you're on main and synced to HEAD
|
||||
* Ensure the project builds and tests run (sanity check only, obviously)
|
||||
* `parallel -j0 exec ::: test/*_test` can help ensure everything at least
|
||||
passes
|
||||
* Prepare release notes
|
||||
* `git log $(git describe --abbrev=0 --tags)..HEAD` gives you the list of
|
||||
commits between the last annotated tag and HEAD
|
||||
* Pick the most interesting.
|
||||
* Create one last commit that updates the version saved in `CMakeLists.txt` to the release version you're creating. (This version will be used if benchmark is installed from the archive you'll be creating in the next step.)
|
||||
|
||||
```
|
||||
project (benchmark VERSION 1.5.3 LANGUAGES CXX)
|
||||
```
|
||||
|
||||
* Create a release through github's interface
|
||||
* Note this will create a lightweight tag.
|
||||
* Update this to an annotated tag:
|
||||
* `git pull --tags`
|
||||
* `git tag -a -f <tag> <tag>`
|
||||
* `git push --force origin`
|
@ -1,203 +0,0 @@
|
||||
# Benchmark Tools
|
||||
|
||||
## compare.py
|
||||
|
||||
The `compare.py` can be used to compare the result of benchmarks.
|
||||
|
||||
### Dependencies
|
||||
The utility relies on the [scipy](https://www.scipy.org) package which can be installed using pip:
|
||||
```bash
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
### Displaying aggregates only
|
||||
|
||||
The switch `-a` / `--display_aggregates_only` can be used to control the
|
||||
displayment of the normal iterations vs the aggregates. When passed, it will
|
||||
be passthrough to the benchmark binaries to be run, and will be accounted for
|
||||
in the tool itself; only the aggregates will be displayed, but not normal runs.
|
||||
It only affects the display, the separate runs will still be used to calculate
|
||||
the U test.
|
||||
|
||||
### Modes of operation
|
||||
|
||||
There are three modes of operation:
|
||||
|
||||
1. Just compare two benchmarks
|
||||
The program is invoked like:
|
||||
|
||||
``` bash
|
||||
$ compare.py benchmarks <benchmark_baseline> <benchmark_contender> [benchmark options]...
|
||||
```
|
||||
Where `<benchmark_baseline>` and `<benchmark_contender>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
|
||||
|
||||
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
|
||||
|
||||
Example output:
|
||||
```
|
||||
$ ./compare.py benchmarks ./a.out ./a.out
|
||||
RUNNING: ./a.out --benchmark_out=/tmp/tmprBT5nW
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:16:44
|
||||
------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------
|
||||
BM_memcpy/8 36 ns 36 ns 19101577 211.669MB/s
|
||||
BM_memcpy/64 76 ns 76 ns 9412571 800.199MB/s
|
||||
BM_memcpy/512 84 ns 84 ns 8249070 5.64771GB/s
|
||||
BM_memcpy/1024 116 ns 116 ns 6181763 8.19505GB/s
|
||||
BM_memcpy/8192 643 ns 643 ns 1062855 11.8636GB/s
|
||||
BM_copy/8 222 ns 222 ns 3137987 34.3772MB/s
|
||||
BM_copy/64 1608 ns 1608 ns 432758 37.9501MB/s
|
||||
BM_copy/512 12589 ns 12589 ns 54806 38.7867MB/s
|
||||
BM_copy/1024 25169 ns 25169 ns 27713 38.8003MB/s
|
||||
BM_copy/8192 201165 ns 201112 ns 3486 38.8466MB/s
|
||||
RUNNING: ./a.out --benchmark_out=/tmp/tmpt1wwG_
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:16:53
|
||||
------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------
|
||||
BM_memcpy/8 36 ns 36 ns 19397903 211.255MB/s
|
||||
BM_memcpy/64 73 ns 73 ns 9691174 839.635MB/s
|
||||
BM_memcpy/512 85 ns 85 ns 8312329 5.60101GB/s
|
||||
BM_memcpy/1024 118 ns 118 ns 6438774 8.11608GB/s
|
||||
BM_memcpy/8192 656 ns 656 ns 1068644 11.6277GB/s
|
||||
BM_copy/8 223 ns 223 ns 3146977 34.2338MB/s
|
||||
BM_copy/64 1611 ns 1611 ns 435340 37.8751MB/s
|
||||
BM_copy/512 12622 ns 12622 ns 54818 38.6844MB/s
|
||||
BM_copy/1024 25257 ns 25239 ns 27779 38.6927MB/s
|
||||
BM_copy/8192 205013 ns 205010 ns 3479 38.108MB/s
|
||||
Comparing ./a.out to ./a.out
|
||||
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||
------------------------------------------------------------------------------------------------------
|
||||
BM_memcpy/8 +0.0020 +0.0020 36 36 36 36
|
||||
BM_memcpy/64 -0.0468 -0.0470 76 73 76 73
|
||||
BM_memcpy/512 +0.0081 +0.0083 84 85 84 85
|
||||
BM_memcpy/1024 +0.0098 +0.0097 116 118 116 118
|
||||
BM_memcpy/8192 +0.0200 +0.0203 643 656 643 656
|
||||
BM_copy/8 +0.0046 +0.0042 222 223 222 223
|
||||
BM_copy/64 +0.0020 +0.0020 1608 1611 1608 1611
|
||||
BM_copy/512 +0.0027 +0.0026 12589 12622 12589 12622
|
||||
BM_copy/1024 +0.0035 +0.0028 25169 25257 25169 25239
|
||||
BM_copy/8192 +0.0191 +0.0194 201165 205013 201112 205010
|
||||
```
|
||||
|
||||
What it does is for the every benchmark from the first run it looks for the benchmark with exactly the same name in the second run, and then compares the results. If the names differ, the benchmark is omitted from the diff.
|
||||
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
|
||||
|
||||
2. Compare two different filters of one benchmark
|
||||
The program is invoked like:
|
||||
|
||||
``` bash
|
||||
$ compare.py filters <benchmark> <filter_baseline> <filter_contender> [benchmark options]...
|
||||
```
|
||||
Where `<benchmark>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
|
||||
|
||||
Where `<filter_baseline>` and `<filter_contender>` are the same regex filters that you would pass to the `[--benchmark_filter=<regex>]` parameter of the benchmark binary.
|
||||
|
||||
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
|
||||
|
||||
Example output:
|
||||
```
|
||||
$ ./compare.py filters ./a.out BM_memcpy BM_copy
|
||||
RUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmpBWKk0k
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:37:28
|
||||
------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------
|
||||
BM_memcpy/8 36 ns 36 ns 17891491 211.215MB/s
|
||||
BM_memcpy/64 74 ns 74 ns 9400999 825.646MB/s
|
||||
BM_memcpy/512 87 ns 87 ns 8027453 5.46126GB/s
|
||||
BM_memcpy/1024 111 ns 111 ns 6116853 8.5648GB/s
|
||||
BM_memcpy/8192 657 ns 656 ns 1064679 11.6247GB/s
|
||||
RUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpAvWcOM
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:37:33
|
||||
----------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
----------------------------------------------------
|
||||
BM_copy/8 227 ns 227 ns 3038700 33.6264MB/s
|
||||
BM_copy/64 1640 ns 1640 ns 426893 37.2154MB/s
|
||||
BM_copy/512 12804 ns 12801 ns 55417 38.1444MB/s
|
||||
BM_copy/1024 25409 ns 25407 ns 27516 38.4365MB/s
|
||||
BM_copy/8192 202986 ns 202990 ns 3454 38.4871MB/s
|
||||
Comparing BM_memcpy to BM_copy (from ./a.out)
|
||||
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
[BM_memcpy vs. BM_copy]/8 +5.2829 +5.2812 36 227 36 227
|
||||
[BM_memcpy vs. BM_copy]/64 +21.1719 +21.1856 74 1640 74 1640
|
||||
[BM_memcpy vs. BM_copy]/512 +145.6487 +145.6097 87 12804 87 12801
|
||||
[BM_memcpy vs. BM_copy]/1024 +227.1860 +227.1776 111 25409 111 25407
|
||||
[BM_memcpy vs. BM_copy]/8192 +308.1664 +308.2898 657 202986 656 202990
|
||||
```
|
||||
|
||||
As you can see, it applies filter to the benchmarks, both when running the benchmark, and before doing the diff. And to make the diff work, the matches are replaced with some common string. Thus, you can compare two different benchmark families within one benchmark binary.
|
||||
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
|
||||
|
||||
3. Compare filter one from benchmark one to filter two from benchmark two:
|
||||
The program is invoked like:
|
||||
|
||||
``` bash
|
||||
$ compare.py filters <benchmark_baseline> <filter_baseline> <benchmark_contender> <filter_contender> [benchmark options]...
|
||||
```
|
||||
|
||||
Where `<benchmark_baseline>` and `<benchmark_contender>` either specify a benchmark executable file, or a JSON output file. The type of the input file is automatically detected. If a benchmark executable is specified then the benchmark is run to obtain the results. Otherwise the results are simply loaded from the output file.
|
||||
|
||||
Where `<filter_baseline>` and `<filter_contender>` are the same regex filters that you would pass to the `[--benchmark_filter=<regex>]` parameter of the benchmark binary.
|
||||
|
||||
`[benchmark options]` will be passed to the benchmarks invocations. They can be anything that binary accepts, be it either normal `--benchmark_*` parameters, or some custom parameters your binary takes.
|
||||
|
||||
Example output:
|
||||
```
|
||||
$ ./compare.py benchmarksfiltered ./a.out BM_memcpy ./a.out BM_copy
|
||||
RUNNING: ./a.out --benchmark_filter=BM_memcpy --benchmark_out=/tmp/tmp_FvbYg
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:38:27
|
||||
------------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
------------------------------------------------------
|
||||
BM_memcpy/8 37 ns 37 ns 18953482 204.118MB/s
|
||||
BM_memcpy/64 74 ns 74 ns 9206578 828.245MB/s
|
||||
BM_memcpy/512 91 ns 91 ns 8086195 5.25476GB/s
|
||||
BM_memcpy/1024 120 ns 120 ns 5804513 7.95662GB/s
|
||||
BM_memcpy/8192 664 ns 664 ns 1028363 11.4948GB/s
|
||||
RUNNING: ./a.out --benchmark_filter=BM_copy --benchmark_out=/tmp/tmpDfL5iE
|
||||
Run on (8 X 4000 MHz CPU s)
|
||||
2017-11-07 21:38:32
|
||||
----------------------------------------------------
|
||||
Benchmark Time CPU Iterations
|
||||
----------------------------------------------------
|
||||
BM_copy/8 230 ns 230 ns 2985909 33.1161MB/s
|
||||
BM_copy/64 1654 ns 1653 ns 419408 36.9137MB/s
|
||||
BM_copy/512 13122 ns 13120 ns 53403 37.2156MB/s
|
||||
BM_copy/1024 26679 ns 26666 ns 26575 36.6218MB/s
|
||||
BM_copy/8192 215068 ns 215053 ns 3221 36.3283MB/s
|
||||
Comparing BM_memcpy (from ./a.out) to BM_copy (from ./a.out)
|
||||
Benchmark Time CPU Time Old Time New CPU Old CPU New
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
[BM_memcpy vs. BM_copy]/8 +5.1649 +5.1637 37 230 37 230
|
||||
[BM_memcpy vs. BM_copy]/64 +21.4352 +21.4374 74 1654 74 1653
|
||||
[BM_memcpy vs. BM_copy]/512 +143.6022 +143.5865 91 13122 91 13120
|
||||
[BM_memcpy vs. BM_copy]/1024 +221.5903 +221.4790 120 26679 120 26666
|
||||
[BM_memcpy vs. BM_copy]/8192 +322.9059 +323.0096 664 215068 664 215053
|
||||
```
|
||||
This is a mix of the previous two modes, two (potentially different) benchmark binaries are run, and a different filter is applied to each one.
|
||||
As you can note, the values in `Time` and `CPU` columns are calculated as `(new - old) / |old|`.
|
||||
|
||||
### U test
|
||||
|
||||
If there is a sufficient repetition count of the benchmarks, the tool can do
|
||||
a [U Test](https://en.wikipedia.org/wiki/Mann%E2%80%93Whitney_U_test), of the
|
||||
null hypothesis that it is equally likely that a randomly selected value from
|
||||
one sample will be less than or greater than a randomly selected value from a
|
||||
second sample.
|
||||
|
||||
If the calculated p-value is below this value is lower than the significance
|
||||
level alpha, then the result is said to be statistically significant and the
|
||||
null hypothesis is rejected. Which in other words means that the two benchmarks
|
||||
aren't identical.
|
||||
|
||||
**WARNING**: requires **LARGE** (no less than 9) number of repetitions to be
|
||||
meaningful!
|
File diff suppressed because it is too large
Load Diff
@ -1,2 +0,0 @@
|
||||
numpy == 1.19.4
|
||||
scipy == 1.5.4
|
@ -1,140 +0,0 @@
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from distutils import sysconfig
|
||||
import setuptools
|
||||
from setuptools.command import build_ext
|
||||
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
IS_WINDOWS = sys.platform.startswith("win")
|
||||
|
||||
|
||||
def _get_version():
|
||||
"""Parse the version string from __init__.py."""
|
||||
with open(
|
||||
os.path.join(HERE, "bindings", "python", "google_benchmark", "__init__.py")
|
||||
) as init_file:
|
||||
try:
|
||||
version_line = next(
|
||||
line for line in init_file if line.startswith("__version__")
|
||||
)
|
||||
except StopIteration:
|
||||
raise ValueError("__version__ not defined in __init__.py")
|
||||
else:
|
||||
namespace = {}
|
||||
exec(version_line, namespace) # pylint: disable=exec-used
|
||||
return namespace["__version__"]
|
||||
|
||||
|
||||
def _parse_requirements(path):
|
||||
with open(os.path.join(HERE, path)) as requirements:
|
||||
return [
|
||||
line.rstrip()
|
||||
for line in requirements
|
||||
if not (line.isspace() or line.startswith("#"))
|
||||
]
|
||||
|
||||
|
||||
class BazelExtension(setuptools.Extension):
|
||||
"""A C/C++ extension that is defined as a Bazel BUILD target."""
|
||||
|
||||
def __init__(self, name, bazel_target):
|
||||
self.bazel_target = bazel_target
|
||||
self.relpath, self.target_name = posixpath.relpath(bazel_target, "//").split(
|
||||
":"
|
||||
)
|
||||
setuptools.Extension.__init__(self, name, sources=[])
|
||||
|
||||
|
||||
class BuildBazelExtension(build_ext.build_ext):
|
||||
"""A command that runs Bazel to build a C/C++ extension."""
|
||||
|
||||
def run(self):
|
||||
for ext in self.extensions:
|
||||
self.bazel_build(ext)
|
||||
build_ext.build_ext.run(self)
|
||||
|
||||
def bazel_build(self, ext):
|
||||
"""Runs the bazel build to create the package."""
|
||||
with open("WORKSPACE", "r") as workspace:
|
||||
workspace_contents = workspace.read()
|
||||
|
||||
with open("WORKSPACE", "w") as workspace:
|
||||
workspace.write(
|
||||
re.sub(
|
||||
r'(?<=path = ").*(?=", # May be overwritten by setup\.py\.)',
|
||||
sysconfig.get_python_inc().replace(os.path.sep, posixpath.sep),
|
||||
workspace_contents,
|
||||
)
|
||||
)
|
||||
|
||||
if not os.path.exists(self.build_temp):
|
||||
os.makedirs(self.build_temp)
|
||||
|
||||
bazel_argv = [
|
||||
"bazel",
|
||||
"build",
|
||||
ext.bazel_target,
|
||||
"--symlink_prefix=" + os.path.join(self.build_temp, "bazel-"),
|
||||
"--compilation_mode=" + ("dbg" if self.debug else "opt"),
|
||||
]
|
||||
|
||||
if IS_WINDOWS:
|
||||
# Link with python*.lib.
|
||||
for library_dir in self.library_dirs:
|
||||
bazel_argv.append("--linkopt=/LIBPATH:" + library_dir)
|
||||
|
||||
self.spawn(bazel_argv)
|
||||
|
||||
shared_lib_suffix = '.dll' if IS_WINDOWS else '.so'
|
||||
ext_bazel_bin_path = os.path.join(
|
||||
self.build_temp, 'bazel-bin',
|
||||
ext.relpath, ext.target_name + shared_lib_suffix)
|
||||
|
||||
ext_dest_path = self.get_ext_fullpath(ext.name)
|
||||
ext_dest_dir = os.path.dirname(ext_dest_path)
|
||||
if not os.path.exists(ext_dest_dir):
|
||||
os.makedirs(ext_dest_dir)
|
||||
shutil.copyfile(ext_bazel_bin_path, ext_dest_path)
|
||||
|
||||
|
||||
setuptools.setup(
|
||||
name="google_benchmark",
|
||||
version=_get_version(),
|
||||
url="https://github.com/google/benchmark",
|
||||
description="A library to benchmark code snippets.",
|
||||
author="Google",
|
||||
author_email="benchmark-py@google.com",
|
||||
# Contained modules and scripts.
|
||||
package_dir={"": "bindings/python"},
|
||||
packages=setuptools.find_packages("bindings/python"),
|
||||
install_requires=_parse_requirements("bindings/python/requirements.txt"),
|
||||
cmdclass=dict(build_ext=BuildBazelExtension),
|
||||
ext_modules=[
|
||||
BazelExtension(
|
||||
"google_benchmark._benchmark",
|
||||
"//bindings/python/google_benchmark:_benchmark",
|
||||
)
|
||||
],
|
||||
zip_safe=False,
|
||||
# PyPI package information.
|
||||
classifiers=[
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"Intended Audience :: Science/Research",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Topic :: Software Development :: Testing",
|
||||
"Topic :: System :: Benchmark",
|
||||
],
|
||||
license="Apache 2.0",
|
||||
keywords="benchmark",
|
||||
)
|
@ -1,120 +0,0 @@
|
||||
# Allow the source files to find headers in src/
|
||||
include(GNUInstallDirs)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||
|
||||
if (DEFINED BENCHMARK_CXX_LINKER_FLAGS)
|
||||
list(APPEND CMAKE_SHARED_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS})
|
||||
list(APPEND CMAKE_MODULE_LINKER_FLAGS ${BENCHMARK_CXX_LINKER_FLAGS})
|
||||
endif()
|
||||
|
||||
file(GLOB
|
||||
SOURCE_FILES
|
||||
*.cc
|
||||
${PROJECT_SOURCE_DIR}/include/benchmark/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/*.h)
|
||||
file(GLOB BENCHMARK_MAIN "benchmark_main.cc")
|
||||
foreach(item ${BENCHMARK_MAIN})
|
||||
list(REMOVE_ITEM SOURCE_FILES "${item}")
|
||||
endforeach()
|
||||
|
||||
add_library(benchmark ${SOURCE_FILES})
|
||||
add_library(benchmark::benchmark ALIAS benchmark)
|
||||
set_target_properties(benchmark PROPERTIES
|
||||
OUTPUT_NAME "benchmark"
|
||||
VERSION ${GENERIC_LIB_VERSION}
|
||||
SOVERSION ${GENERIC_LIB_SOVERSION}
|
||||
)
|
||||
target_include_directories(benchmark PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||
)
|
||||
|
||||
# libpfm, if available
|
||||
if (HAVE_LIBPFM)
|
||||
target_link_libraries(benchmark libpfm.a)
|
||||
add_definitions(-DHAVE_LIBPFM)
|
||||
endif()
|
||||
|
||||
# Link threads.
|
||||
target_link_libraries(benchmark ${BENCHMARK_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
find_library(LIBRT rt)
|
||||
if(LIBRT)
|
||||
target_link_libraries(benchmark ${LIBRT})
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE)
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UPPER)
|
||||
endif()
|
||||
if(NOT CMAKE_THREAD_LIBS_INIT AND "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}" MATCHES ".*-fsanitize=[^ ]*address.*")
|
||||
message(WARNING "CMake's FindThreads.cmake did not fail, but CMAKE_THREAD_LIBS_INIT ended up being empty. This was fixed in https://github.com/Kitware/CMake/commit/d53317130e84898c5328c237186dbd995aaf1c12 Let's guess that -pthread is sufficient.")
|
||||
target_link_libraries(benchmark -pthread)
|
||||
endif()
|
||||
|
||||
# We need extra libraries on Windows
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
target_link_libraries(benchmark shlwapi)
|
||||
endif()
|
||||
|
||||
# We need extra libraries on Solaris
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
target_link_libraries(benchmark kstat)
|
||||
endif()
|
||||
|
||||
# Benchmark main library
|
||||
add_library(benchmark_main "benchmark_main.cc")
|
||||
add_library(benchmark::benchmark_main ALIAS benchmark_main)
|
||||
set_target_properties(benchmark_main PROPERTIES
|
||||
OUTPUT_NAME "benchmark_main"
|
||||
VERSION ${GENERIC_LIB_VERSION}
|
||||
SOVERSION ${GENERIC_LIB_SOVERSION}
|
||||
)
|
||||
target_include_directories(benchmark PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
||||
)
|
||||
target_link_libraries(benchmark_main benchmark::benchmark)
|
||||
|
||||
|
||||
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||
|
||||
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
|
||||
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
|
||||
set(pkg_config "${generated_dir}/${PROJECT_NAME}.pc")
|
||||
set(targets_export_name "${PROJECT_NAME}Targets")
|
||||
|
||||
set(namespace "${PROJECT_NAME}::")
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
"${version_config}" VERSION ${GENERIC_LIB_VERSION} COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in" "${project_config}" @ONLY)
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/benchmark.pc.in" "${pkg_config}" @ONLY)
|
||||
|
||||
if (BENCHMARK_ENABLE_INSTALL)
|
||||
# Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable)
|
||||
install(
|
||||
TARGETS benchmark benchmark_main
|
||||
EXPORT ${targets_export_name}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
install(
|
||||
DIRECTORY "${PROJECT_SOURCE_DIR}/include/benchmark"
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
FILES_MATCHING PATTERN "*.*h")
|
||||
|
||||
install(
|
||||
FILES "${project_config}" "${version_config}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
|
||||
install(
|
||||
FILES "${pkg_config}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
|
||||
install(
|
||||
EXPORT "${targets_export_name}"
|
||||
NAMESPACE "${namespace}"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
endif()
|
@ -1,33 +0,0 @@
|
||||
#ifndef BENCHMARK_ARRAYSIZE_H_
|
||||
#define BENCHMARK_ARRAYSIZE_H_
|
||||
|
||||
#include "internal_macros.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
// The arraysize(arr) macro returns the # of elements in an array arr.
|
||||
// The expression is a compile-time constant, and therefore can be
|
||||
// used in defining new arrays, for example. If you use arraysize on
|
||||
// a pointer by mistake, you will get a compile-time error.
|
||||
//
|
||||
|
||||
// This template function declaration is used in defining arraysize.
|
||||
// Note that the function doesn't need an implementation, as we only
|
||||
// use its type.
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||
|
||||
// That gcc wants both of these prototypes seems mysterious. VC, for
|
||||
// its part, can't decide which to use (another mystery). Matching of
|
||||
// template overloads: the final frontier.
|
||||
#ifndef COMPILER_MSVC
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(const T (&array)[N]))[N];
|
||||
#endif
|
||||
|
||||
#define arraysize(array) (sizeof(::benchmark::internal::ArraySizeHelper(array)))
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_ARRAYSIZE_H_
|
@ -1,617 +0,0 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
|
||||
#include "benchmark_api_internal.h"
|
||||
#include "benchmark_runner.h"
|
||||
#include "internal_macros.h"
|
||||
|
||||
#ifndef BENCHMARK_OS_WINDOWS
|
||||
#ifndef BENCHMARK_OS_FUCHSIA
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "check.h"
|
||||
#include "colorprint.h"
|
||||
#include "commandlineflags.h"
|
||||
#include "complexity.h"
|
||||
#include "counter.h"
|
||||
#include "internal_macros.h"
|
||||
#include "log.h"
|
||||
#include "mutex.h"
|
||||
#include "perf_counters.h"
|
||||
#include "re.h"
|
||||
#include "statistics.h"
|
||||
#include "string_util.h"
|
||||
#include "thread_manager.h"
|
||||
#include "thread_timer.h"
|
||||
|
||||
// Print a list of benchmarks. This option overrides all other options.
|
||||
DEFINE_bool(benchmark_list_tests, false);
|
||||
|
||||
// A regular expression that specifies the set of benchmarks to execute. If
|
||||
// this flag is empty, or if this flag is the string \"all\", all benchmarks
|
||||
// linked into the binary are run.
|
||||
DEFINE_string(benchmark_filter, ".");
|
||||
|
||||
// Minimum number of seconds we should run benchmark before results are
|
||||
// considered significant. For cpu-time based tests, this is the lower bound
|
||||
// on the total cpu time used by all threads that make up the test. For
|
||||
// real-time based tests, this is the lower bound on the elapsed time of the
|
||||
// benchmark execution, regardless of number of threads.
|
||||
DEFINE_double(benchmark_min_time, 0.5);
|
||||
|
||||
// The number of runs of each benchmark. If greater than 1, the mean and
|
||||
// standard deviation of the runs will be reported.
|
||||
DEFINE_int32(benchmark_repetitions, 1);
|
||||
|
||||
// If set, enable random interleaving of repetitions of all benchmarks.
|
||||
// See http://github.com/google/benchmark/issues/1051 for details.
|
||||
DEFINE_bool(benchmark_enable_random_interleaving, false);
|
||||
|
||||
// Report the result of each benchmark repetitions. When 'true' is specified
|
||||
// only the mean, standard deviation, and other statistics are reported for
|
||||
// repeated benchmarks. Affects all reporters.
|
||||
DEFINE_bool(benchmark_report_aggregates_only, false);
|
||||
|
||||
// Display the result of each benchmark repetitions. When 'true' is specified
|
||||
// only the mean, standard deviation, and other statistics are displayed for
|
||||
// repeated benchmarks. Unlike benchmark_report_aggregates_only, only affects
|
||||
// the display reporter, but *NOT* file reporter, which will still contain
|
||||
// all the output.
|
||||
DEFINE_bool(benchmark_display_aggregates_only, false);
|
||||
|
||||
// The format to use for console output.
|
||||
// Valid values are 'console', 'json', or 'csv'.
|
||||
DEFINE_string(benchmark_format, "console");
|
||||
|
||||
// The format to use for file output.
|
||||
// Valid values are 'console', 'json', or 'csv'.
|
||||
DEFINE_string(benchmark_out_format, "json");
|
||||
|
||||
// The file to write additional output to.
|
||||
DEFINE_string(benchmark_out, "");
|
||||
|
||||
// Whether to use colors in the output. Valid values:
|
||||
// 'true'/'yes'/1, 'false'/'no'/0, and 'auto'. 'auto' means to use colors if
|
||||
// the output is being sent to a terminal and the TERM environment variable is
|
||||
// set to a terminal type that supports colors.
|
||||
DEFINE_string(benchmark_color, "auto");
|
||||
|
||||
// Whether to use tabular format when printing user counters to the console.
|
||||
// Valid values: 'true'/'yes'/1, 'false'/'no'/0. Defaults to false.
|
||||
DEFINE_bool(benchmark_counters_tabular, false);
|
||||
|
||||
// The level of verbose logging to output
|
||||
DEFINE_int32(v, 0);
|
||||
|
||||
// List of additional perf counters to collect, in libpfm format. For more
|
||||
// information about libpfm: https://man7.org/linux/man-pages/man3/libpfm.3.html
|
||||
DEFINE_string(benchmark_perf_counters, "");
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
// Extra context to include in the output formatted as comma-separated key-value
|
||||
// pairs. Kept internal as it's only used for parsing from env/command line.
|
||||
DEFINE_kvpairs(benchmark_context, {});
|
||||
|
||||
std::map<std::string, std::string>* global_context = nullptr;
|
||||
|
||||
// FIXME: wouldn't LTO mess this up?
|
||||
void UseCharPointer(char const volatile*) {}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
State::State(IterationCount max_iters, const std::vector<int64_t>& ranges,
|
||||
int thread_i, int n_threads, internal::ThreadTimer* timer,
|
||||
internal::ThreadManager* manager,
|
||||
internal::PerfCountersMeasurement* perf_counters_measurement)
|
||||
: total_iterations_(0),
|
||||
batch_leftover_(0),
|
||||
max_iterations(max_iters),
|
||||
started_(false),
|
||||
finished_(false),
|
||||
error_occurred_(false),
|
||||
range_(ranges),
|
||||
complexity_n_(0),
|
||||
counters(),
|
||||
thread_index(thread_i),
|
||||
threads(n_threads),
|
||||
timer_(timer),
|
||||
manager_(manager),
|
||||
perf_counters_measurement_(perf_counters_measurement) {
|
||||
CHECK(max_iterations != 0) << "At least one iteration must be run";
|
||||
CHECK_LT(thread_index, threads) << "thread_index must be less than threads";
|
||||
|
||||
// Note: The use of offsetof below is technically undefined until C++17
|
||||
// because State is not a standard layout type. However, all compilers
|
||||
// currently provide well-defined behavior as an extension (which is
|
||||
// demonstrated since constexpr evaluation must diagnose all undefined
|
||||
// behavior). However, GCC and Clang also warn about this use of offsetof,
|
||||
// which must be suppressed.
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#pragma warning push
|
||||
#pragma warning(disable : 1875)
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
||||
#endif
|
||||
// Offset tests to ensure commonly accessed data is on the first cache line.
|
||||
const int cache_line_size = 64;
|
||||
static_assert(offsetof(State, error_occurred_) <=
|
||||
(cache_line_size - sizeof(error_occurred_)),
|
||||
"");
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#pragma warning pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
void State::PauseTiming() {
|
||||
// Add in time accumulated so far
|
||||
CHECK(started_ && !finished_ && !error_occurred_);
|
||||
timer_->StopTimer();
|
||||
if (perf_counters_measurement_) {
|
||||
auto measurements = perf_counters_measurement_->StopAndGetMeasurements();
|
||||
for (const auto& name_and_measurement : measurements) {
|
||||
auto name = name_and_measurement.first;
|
||||
auto measurement = name_and_measurement.second;
|
||||
CHECK_EQ(counters[name], 0.0);
|
||||
counters[name] = Counter(measurement, Counter::kAvgIterations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void State::ResumeTiming() {
|
||||
CHECK(started_ && !finished_ && !error_occurred_);
|
||||
timer_->StartTimer();
|
||||
if (perf_counters_measurement_) {
|
||||
perf_counters_measurement_->Start();
|
||||
}
|
||||
}
|
||||
|
||||
void State::SkipWithError(const char* msg) {
|
||||
CHECK(msg);
|
||||
error_occurred_ = true;
|
||||
{
|
||||
MutexLock l(manager_->GetBenchmarkMutex());
|
||||
if (manager_->results.has_error_ == false) {
|
||||
manager_->results.error_message_ = msg;
|
||||
manager_->results.has_error_ = true;
|
||||
}
|
||||
}
|
||||
total_iterations_ = 0;
|
||||
if (timer_->running()) timer_->StopTimer();
|
||||
}
|
||||
|
||||
void State::SetIterationTime(double seconds) {
|
||||
timer_->SetIterationTime(seconds);
|
||||
}
|
||||
|
||||
void State::SetLabel(const char* label) {
|
||||
MutexLock l(manager_->GetBenchmarkMutex());
|
||||
manager_->results.report_label_ = label;
|
||||
}
|
||||
|
||||
void State::StartKeepRunning() {
|
||||
CHECK(!started_ && !finished_);
|
||||
started_ = true;
|
||||
total_iterations_ = error_occurred_ ? 0 : max_iterations;
|
||||
manager_->StartStopBarrier();
|
||||
if (!error_occurred_) ResumeTiming();
|
||||
}
|
||||
|
||||
void State::FinishKeepRunning() {
|
||||
CHECK(started_ && (!finished_ || error_occurred_));
|
||||
if (!error_occurred_) {
|
||||
PauseTiming();
|
||||
}
|
||||
// Total iterations has now wrapped around past 0. Fix this.
|
||||
total_iterations_ = 0;
|
||||
finished_ = true;
|
||||
manager_->StartStopBarrier();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
// Flushes streams after invoking reporter methods that write to them. This
|
||||
// ensures users get timely updates even when streams are not line-buffered.
|
||||
void FlushStreams(BenchmarkReporter* reporter) {
|
||||
if (!reporter) return;
|
||||
std::flush(reporter->GetOutputStream());
|
||||
std::flush(reporter->GetErrorStream());
|
||||
}
|
||||
|
||||
// Reports in both display and file reporters.
|
||||
void Report(BenchmarkReporter* display_reporter,
|
||||
BenchmarkReporter* file_reporter, const RunResults& run_results) {
|
||||
auto report_one = [](BenchmarkReporter* reporter, bool aggregates_only,
|
||||
const RunResults& results) {
|
||||
assert(reporter);
|
||||
// If there are no aggregates, do output non-aggregates.
|
||||
aggregates_only &= !results.aggregates_only.empty();
|
||||
if (!aggregates_only) reporter->ReportRuns(results.non_aggregates);
|
||||
if (!results.aggregates_only.empty())
|
||||
reporter->ReportRuns(results.aggregates_only);
|
||||
};
|
||||
|
||||
report_one(display_reporter, run_results.display_report_aggregates_only,
|
||||
run_results);
|
||||
if (file_reporter)
|
||||
report_one(file_reporter, run_results.file_report_aggregates_only,
|
||||
run_results);
|
||||
|
||||
FlushStreams(display_reporter);
|
||||
FlushStreams(file_reporter);
|
||||
}
|
||||
|
||||
void RunBenchmarks(const std::vector<BenchmarkInstance>& benchmarks,
|
||||
BenchmarkReporter* display_reporter,
|
||||
BenchmarkReporter* file_reporter) {
|
||||
// Note the file_reporter can be null.
|
||||
CHECK(display_reporter != nullptr);
|
||||
|
||||
// Determine the width of the name field using a minimum width of 10.
|
||||
bool might_have_aggregates = FLAGS_benchmark_repetitions > 1;
|
||||
size_t name_field_width = 10;
|
||||
size_t stat_field_width = 0;
|
||||
for (const BenchmarkInstance& benchmark : benchmarks) {
|
||||
name_field_width =
|
||||
std::max<size_t>(name_field_width, benchmark.name().str().size());
|
||||
might_have_aggregates |= benchmark.repetitions() > 1;
|
||||
|
||||
for (const auto& Stat : benchmark.statistics())
|
||||
stat_field_width = std::max<size_t>(stat_field_width, Stat.name_.size());
|
||||
}
|
||||
if (might_have_aggregates) name_field_width += 1 + stat_field_width;
|
||||
|
||||
// Print header here
|
||||
BenchmarkReporter::Context context;
|
||||
context.name_field_width = name_field_width;
|
||||
|
||||
// Keep track of running times of all instances of each benchmark family.
|
||||
std::map<int /*family_index*/, BenchmarkReporter::PerFamilyRunReports>
|
||||
per_family_reports;
|
||||
|
||||
if (display_reporter->ReportContext(context) &&
|
||||
(!file_reporter || file_reporter->ReportContext(context))) {
|
||||
FlushStreams(display_reporter);
|
||||
FlushStreams(file_reporter);
|
||||
|
||||
size_t num_repetitions_total = 0;
|
||||
|
||||
std::vector<internal::BenchmarkRunner> runners;
|
||||
runners.reserve(benchmarks.size());
|
||||
for (const BenchmarkInstance& benchmark : benchmarks) {
|
||||
BenchmarkReporter::PerFamilyRunReports* reports_for_family = nullptr;
|
||||
if (benchmark.complexity() != oNone)
|
||||
reports_for_family = &per_family_reports[benchmark.family_index()];
|
||||
|
||||
runners.emplace_back(benchmark, reports_for_family);
|
||||
int num_repeats_of_this_instance = runners.back().GetNumRepeats();
|
||||
num_repetitions_total += num_repeats_of_this_instance;
|
||||
if (reports_for_family)
|
||||
reports_for_family->num_runs_total += num_repeats_of_this_instance;
|
||||
}
|
||||
assert(runners.size() == benchmarks.size() && "Unexpected runner count.");
|
||||
|
||||
std::vector<int> repetition_indices;
|
||||
repetition_indices.reserve(num_repetitions_total);
|
||||
for (size_t runner_index = 0, num_runners = runners.size();
|
||||
runner_index != num_runners; ++runner_index) {
|
||||
const internal::BenchmarkRunner& runner = runners[runner_index];
|
||||
std::fill_n(std::back_inserter(repetition_indices),
|
||||
runner.GetNumRepeats(), runner_index);
|
||||
}
|
||||
assert(repetition_indices.size() == num_repetitions_total &&
|
||||
"Unexpected number of repetition indexes.");
|
||||
|
||||
if (FLAGS_benchmark_enable_random_interleaving) {
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
std::shuffle(repetition_indices.begin(), repetition_indices.end(), g);
|
||||
}
|
||||
|
||||
for (size_t repetition_index : repetition_indices) {
|
||||
internal::BenchmarkRunner& runner = runners[repetition_index];
|
||||
runner.DoOneRepetition();
|
||||
if (runner.HasRepeatsRemaining()) continue;
|
||||
// FIXME: report each repetition separately, not all of them in bulk.
|
||||
|
||||
RunResults run_results = runner.GetResults();
|
||||
|
||||
// Maybe calculate complexity report
|
||||
if (const auto* reports_for_family = runner.GetReportsForFamily()) {
|
||||
if (reports_for_family->num_runs_done ==
|
||||
reports_for_family->num_runs_total) {
|
||||
auto additional_run_stats = ComputeBigO(reports_for_family->Runs);
|
||||
run_results.aggregates_only.insert(run_results.aggregates_only.end(),
|
||||
additional_run_stats.begin(),
|
||||
additional_run_stats.end());
|
||||
per_family_reports.erase(
|
||||
(int)reports_for_family->Runs.front().family_index);
|
||||
}
|
||||
}
|
||||
|
||||
Report(display_reporter, file_reporter, run_results);
|
||||
}
|
||||
}
|
||||
display_reporter->Finalize();
|
||||
if (file_reporter) file_reporter->Finalize();
|
||||
FlushStreams(display_reporter);
|
||||
FlushStreams(file_reporter);
|
||||
}
|
||||
|
||||
// Disable deprecated warnings temporarily because we need to reference
|
||||
// CSVReporter but don't want to trigger -Werror=-Wdeprecated-declarations
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
std::unique_ptr<BenchmarkReporter> CreateReporter(
|
||||
std::string const& name, ConsoleReporter::OutputOptions output_opts) {
|
||||
typedef std::unique_ptr<BenchmarkReporter> PtrType;
|
||||
if (name == "console") {
|
||||
return PtrType(new ConsoleReporter(output_opts));
|
||||
} else if (name == "json") {
|
||||
return PtrType(new JSONReporter);
|
||||
} else if (name == "csv") {
|
||||
return PtrType(new CSVReporter);
|
||||
} else {
|
||||
std::cerr << "Unexpected format: '" << name << "'\n";
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // end namespace
|
||||
|
||||
bool IsZero(double n) {
|
||||
return std::abs(n) < std::numeric_limits<double>::epsilon();
|
||||
}
|
||||
|
||||
ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color) {
|
||||
int output_opts = ConsoleReporter::OO_Defaults;
|
||||
auto is_benchmark_color = [force_no_color]() -> bool {
|
||||
if (force_no_color) {
|
||||
return false;
|
||||
}
|
||||
if (FLAGS_benchmark_color == "auto") {
|
||||
return IsColorTerminal();
|
||||
}
|
||||
return IsTruthyFlagValue(FLAGS_benchmark_color);
|
||||
};
|
||||
if (is_benchmark_color()) {
|
||||
output_opts |= ConsoleReporter::OO_Color;
|
||||
} else {
|
||||
output_opts &= ~ConsoleReporter::OO_Color;
|
||||
}
|
||||
if (FLAGS_benchmark_counters_tabular) {
|
||||
output_opts |= ConsoleReporter::OO_Tabular;
|
||||
} else {
|
||||
output_opts &= ~ConsoleReporter::OO_Tabular;
|
||||
}
|
||||
return static_cast<ConsoleReporter::OutputOptions>(output_opts);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
size_t RunSpecifiedBenchmarks() {
|
||||
return RunSpecifiedBenchmarks(nullptr, nullptr);
|
||||
}
|
||||
|
||||
size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter) {
|
||||
return RunSpecifiedBenchmarks(display_reporter, nullptr);
|
||||
}
|
||||
|
||||
size_t RunSpecifiedBenchmarks(BenchmarkReporter* display_reporter,
|
||||
BenchmarkReporter* file_reporter) {
|
||||
std::string spec = FLAGS_benchmark_filter;
|
||||
if (spec.empty() || spec == "all")
|
||||
spec = "."; // Regexp that matches all benchmarks
|
||||
|
||||
// Setup the reporters
|
||||
std::ofstream output_file;
|
||||
std::unique_ptr<BenchmarkReporter> default_display_reporter;
|
||||
std::unique_ptr<BenchmarkReporter> default_file_reporter;
|
||||
if (!display_reporter) {
|
||||
default_display_reporter = internal::CreateReporter(
|
||||
FLAGS_benchmark_format, internal::GetOutputOptions());
|
||||
display_reporter = default_display_reporter.get();
|
||||
}
|
||||
auto& Out = display_reporter->GetOutputStream();
|
||||
auto& Err = display_reporter->GetErrorStream();
|
||||
|
||||
std::string const& fname = FLAGS_benchmark_out;
|
||||
if (fname.empty() && file_reporter) {
|
||||
Err << "A custom file reporter was provided but "
|
||||
"--benchmark_out=<file> was not specified."
|
||||
<< std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
if (!fname.empty()) {
|
||||
output_file.open(fname);
|
||||
if (!output_file.is_open()) {
|
||||
Err << "invalid file name: '" << fname << "'" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
if (!file_reporter) {
|
||||
default_file_reporter = internal::CreateReporter(
|
||||
FLAGS_benchmark_out_format, ConsoleReporter::OO_None);
|
||||
file_reporter = default_file_reporter.get();
|
||||
}
|
||||
file_reporter->SetOutputStream(&output_file);
|
||||
file_reporter->SetErrorStream(&output_file);
|
||||
}
|
||||
|
||||
std::vector<internal::BenchmarkInstance> benchmarks;
|
||||
if (!FindBenchmarksInternal(spec, &benchmarks, &Err)) return 0;
|
||||
|
||||
if (benchmarks.empty()) {
|
||||
Err << "Failed to match any benchmarks against regex: " << spec << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FLAGS_benchmark_list_tests) {
|
||||
for (auto const& benchmark : benchmarks)
|
||||
Out << benchmark.name().str() << "\n";
|
||||
} else {
|
||||
internal::RunBenchmarks(benchmarks, display_reporter, file_reporter);
|
||||
}
|
||||
|
||||
return benchmarks.size();
|
||||
}
|
||||
|
||||
void RegisterMemoryManager(MemoryManager* manager) {
|
||||
internal::memory_manager = manager;
|
||||
}
|
||||
|
||||
void AddCustomContext(const std::string& key, const std::string& value) {
|
||||
if (internal::global_context == nullptr) {
|
||||
internal::global_context = new std::map<std::string, std::string>();
|
||||
}
|
||||
if (!internal::global_context->emplace(key, value).second) {
|
||||
std::cerr << "Failed to add custom context \"" << key << "\" as it already "
|
||||
<< "exists with value \"" << value << "\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
void PrintUsageAndExit() {
|
||||
fprintf(stdout,
|
||||
"benchmark"
|
||||
" [--benchmark_list_tests={true|false}]\n"
|
||||
" [--benchmark_filter=<regex>]\n"
|
||||
" [--benchmark_min_time=<min_time>]\n"
|
||||
" [--benchmark_repetitions=<num_repetitions>]\n"
|
||||
" [--benchmark_enable_random_interleaving={true|false}]\n"
|
||||
" [--benchmark_report_aggregates_only={true|false}]\n"
|
||||
" [--benchmark_display_aggregates_only={true|false}]\n"
|
||||
" [--benchmark_format=<console|json|csv>]\n"
|
||||
" [--benchmark_out=<filename>]\n"
|
||||
" [--benchmark_out_format=<json|console|csv>]\n"
|
||||
" [--benchmark_color={auto|true|false}]\n"
|
||||
" [--benchmark_counters_tabular={true|false}]\n"
|
||||
" [--benchmark_context=<key>=<value>,...]\n"
|
||||
" [--v=<verbosity>]\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void ParseCommandLineFlags(int* argc, char** argv) {
|
||||
using namespace benchmark;
|
||||
BenchmarkReporter::Context::executable_name =
|
||||
(argc && *argc > 0) ? argv[0] : "unknown";
|
||||
for (int i = 1; argc && i < *argc; ++i) {
|
||||
if (ParseBoolFlag(argv[i], "benchmark_list_tests",
|
||||
&FLAGS_benchmark_list_tests) ||
|
||||
ParseStringFlag(argv[i], "benchmark_filter", &FLAGS_benchmark_filter) ||
|
||||
ParseDoubleFlag(argv[i], "benchmark_min_time",
|
||||
&FLAGS_benchmark_min_time) ||
|
||||
ParseInt32Flag(argv[i], "benchmark_repetitions",
|
||||
&FLAGS_benchmark_repetitions) ||
|
||||
ParseBoolFlag(argv[i], "benchmark_enable_random_interleaving",
|
||||
&FLAGS_benchmark_enable_random_interleaving) ||
|
||||
ParseBoolFlag(argv[i], "benchmark_report_aggregates_only",
|
||||
&FLAGS_benchmark_report_aggregates_only) ||
|
||||
ParseBoolFlag(argv[i], "benchmark_display_aggregates_only",
|
||||
&FLAGS_benchmark_display_aggregates_only) ||
|
||||
ParseStringFlag(argv[i], "benchmark_format", &FLAGS_benchmark_format) ||
|
||||
ParseStringFlag(argv[i], "benchmark_out", &FLAGS_benchmark_out) ||
|
||||
ParseStringFlag(argv[i], "benchmark_out_format",
|
||||
&FLAGS_benchmark_out_format) ||
|
||||
ParseStringFlag(argv[i], "benchmark_color", &FLAGS_benchmark_color) ||
|
||||
// "color_print" is the deprecated name for "benchmark_color".
|
||||
// TODO: Remove this.
|
||||
ParseStringFlag(argv[i], "color_print", &FLAGS_benchmark_color) ||
|
||||
ParseBoolFlag(argv[i], "benchmark_counters_tabular",
|
||||
&FLAGS_benchmark_counters_tabular) ||
|
||||
ParseStringFlag(argv[i], "benchmark_perf_counters",
|
||||
&FLAGS_benchmark_perf_counters) ||
|
||||
ParseKeyValueFlag(argv[i], "benchmark_context",
|
||||
&FLAGS_benchmark_context) ||
|
||||
ParseInt32Flag(argv[i], "v", &FLAGS_v)) {
|
||||
for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1];
|
||||
|
||||
--(*argc);
|
||||
--i;
|
||||
} else if (IsFlag(argv[i], "help")) {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
}
|
||||
for (auto const* flag :
|
||||
{&FLAGS_benchmark_format, &FLAGS_benchmark_out_format}) {
|
||||
if (*flag != "console" && *flag != "json" && *flag != "csv") {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
}
|
||||
if (FLAGS_benchmark_color.empty()) {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
for (const auto& kv : FLAGS_benchmark_context) {
|
||||
AddCustomContext(kv.first, kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
int InitializeStreams() {
|
||||
static std::ios_base::Init init;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
void Initialize(int* argc, char** argv) {
|
||||
internal::ParseCommandLineFlags(argc, argv);
|
||||
internal::LogLevel() = FLAGS_v;
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
delete internal::global_context;
|
||||
}
|
||||
|
||||
bool ReportUnrecognizedArguments(int argc, char** argv) {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
fprintf(stderr, "%s: error: unrecognized command-line flag: %s\n", argv[0],
|
||||
argv[i]);
|
||||
}
|
||||
return argc > 1;
|
||||
}
|
||||
|
||||
} // end namespace benchmark
|
@ -1,94 +0,0 @@
|
||||
#include "benchmark_api_internal.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
#include "string_util.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx,
|
||||
int per_family_instance_idx,
|
||||
const std::vector<int64_t>& args,
|
||||
int thread_count)
|
||||
: benchmark_(*benchmark),
|
||||
family_index_(family_idx),
|
||||
per_family_instance_index_(per_family_instance_idx),
|
||||
aggregation_report_mode_(benchmark_.aggregation_report_mode_),
|
||||
args_(args),
|
||||
time_unit_(benchmark_.time_unit_),
|
||||
measure_process_cpu_time_(benchmark_.measure_process_cpu_time_),
|
||||
use_real_time_(benchmark_.use_real_time_),
|
||||
use_manual_time_(benchmark_.use_manual_time_),
|
||||
complexity_(benchmark_.complexity_),
|
||||
complexity_lambda_(benchmark_.complexity_lambda_),
|
||||
statistics_(benchmark_.statistics_),
|
||||
repetitions_(benchmark_.repetitions_),
|
||||
min_time_(benchmark_.min_time_),
|
||||
iterations_(benchmark_.iterations_),
|
||||
threads_(thread_count) {
|
||||
name_.function_name = benchmark_.name_;
|
||||
|
||||
size_t arg_i = 0;
|
||||
for (const auto& arg : args) {
|
||||
if (!name_.args.empty()) {
|
||||
name_.args += '/';
|
||||
}
|
||||
|
||||
if (arg_i < benchmark->arg_names_.size()) {
|
||||
const auto& arg_name = benchmark_.arg_names_[arg_i];
|
||||
if (!arg_name.empty()) {
|
||||
name_.args += StrFormat("%s:", arg_name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
name_.args += StrFormat("%" PRId64, arg);
|
||||
++arg_i;
|
||||
}
|
||||
|
||||
if (!IsZero(benchmark->min_time_)) {
|
||||
name_.min_time = StrFormat("min_time:%0.3f", benchmark_.min_time_);
|
||||
}
|
||||
|
||||
if (benchmark_.iterations_ != 0) {
|
||||
name_.iterations = StrFormat(
|
||||
"iterations:%lu", static_cast<unsigned long>(benchmark_.iterations_));
|
||||
}
|
||||
|
||||
if (benchmark_.repetitions_ != 0) {
|
||||
name_.repetitions = StrFormat("repeats:%d", benchmark_.repetitions_);
|
||||
}
|
||||
|
||||
if (benchmark_.measure_process_cpu_time_) {
|
||||
name_.time_type = "process_time";
|
||||
}
|
||||
|
||||
if (benchmark_.use_manual_time_) {
|
||||
if (!name_.time_type.empty()) {
|
||||
name_.time_type += '/';
|
||||
}
|
||||
name_.time_type += "manual_time";
|
||||
} else if (benchmark_.use_real_time_) {
|
||||
if (!name_.time_type.empty()) {
|
||||
name_.time_type += '/';
|
||||
}
|
||||
name_.time_type += "real_time";
|
||||
}
|
||||
|
||||
if (!benchmark_.thread_counts_.empty()) {
|
||||
name_.threads = StrFormat("threads:%d", threads_);
|
||||
}
|
||||
}
|
||||
|
||||
State BenchmarkInstance::Run(
|
||||
IterationCount iters, int thread_id, internal::ThreadTimer* timer,
|
||||
internal::ThreadManager* manager,
|
||||
internal::PerfCountersMeasurement* perf_counters_measurement) const {
|
||||
State st(iters, args_, thread_id, threads_, timer, manager,
|
||||
perf_counters_measurement);
|
||||
benchmark_.Run(st);
|
||||
return st;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace benchmark
|
@ -1,78 +0,0 @@
|
||||
#ifndef BENCHMARK_API_INTERNAL_H
|
||||
#define BENCHMARK_API_INTERNAL_H
|
||||
|
||||
#include <cmath>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "commandlineflags.h"
|
||||
|
||||
namespace benchmark {
|
||||
namespace internal {
|
||||
|
||||
// Information kept per benchmark we may want to run
|
||||
class BenchmarkInstance {
|
||||
public:
|
||||
BenchmarkInstance(Benchmark* benchmark, int family_index,
|
||||
int per_family_instance_index,
|
||||
const std::vector<int64_t>& args, int threads);
|
||||
|
||||
const BenchmarkName& name() const { return name_; }
|
||||
int family_index() const { return family_index_; }
|
||||
int per_family_instance_index() const { return per_family_instance_index_; }
|
||||
AggregationReportMode aggregation_report_mode() const {
|
||||
return aggregation_report_mode_;
|
||||
}
|
||||
TimeUnit time_unit() const { return time_unit_; }
|
||||
bool measure_process_cpu_time() const { return measure_process_cpu_time_; }
|
||||
bool use_real_time() const { return use_real_time_; }
|
||||
bool use_manual_time() const { return use_manual_time_; }
|
||||
BigO complexity() const { return complexity_; }
|
||||
BigOFunc& complexity_lambda() const { return *complexity_lambda_; }
|
||||
const std::vector<Statistics>& statistics() const { return statistics_; }
|
||||
int repetitions() const { return repetitions_; }
|
||||
double min_time() const { return min_time_; }
|
||||
IterationCount iterations() const { return iterations_; }
|
||||
int threads() const { return threads_; }
|
||||
|
||||
State Run(IterationCount iters, int thread_id, internal::ThreadTimer* timer,
|
||||
internal::ThreadManager* manager,
|
||||
internal::PerfCountersMeasurement* perf_counters_measurement) const;
|
||||
|
||||
private:
|
||||
BenchmarkName name_;
|
||||
Benchmark& benchmark_;
|
||||
const int family_index_;
|
||||
const int per_family_instance_index_;
|
||||
AggregationReportMode aggregation_report_mode_;
|
||||
const std::vector<int64_t>& args_;
|
||||
TimeUnit time_unit_;
|
||||
bool measure_process_cpu_time_;
|
||||
bool use_real_time_;
|
||||
bool use_manual_time_;
|
||||
BigO complexity_;
|
||||
BigOFunc* complexity_lambda_;
|
||||
UserCounters counters_;
|
||||
const std::vector<Statistics>& statistics_;
|
||||
int repetitions_;
|
||||
double min_time_;
|
||||
IterationCount iterations_;
|
||||
int threads_; // Number of concurrent threads to us
|
||||
};
|
||||
|
||||
bool FindBenchmarksInternal(const std::string& re,
|
||||
std::vector<BenchmarkInstance>* benchmarks,
|
||||
std::ostream* Err);
|
||||
|
||||
bool IsZero(double n);
|
||||
|
||||
ConsoleReporter::OutputOptions GetOutputOptions(bool force_no_color = false);
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace benchmark
|
||||
|
||||
#endif // BENCHMARK_API_INTERNAL_H
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
//
|
||||
// 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 "benchmark/benchmark.h"
|
||||
|
||||
BENCHMARK_MAIN();
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user