Skip to content

Commit

Permalink
WIP add compilation_time benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
YarikTH committed Aug 20, 2023
1 parent 0ac1521 commit a88ea0e
Show file tree
Hide file tree
Showing 7 changed files with 470 additions and 0 deletions.
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ FetchContent_MakeAvailable(nanobench)
# gersemi: on

add_subdirectory(self_contained)
add_subdirectory(compilation_time)
add_subdirectory(src)
41 changes: 41 additions & 0 deletions tests/compilation_time/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#
# Copyright (C) 2020-2023 Krylov Yaroslav.
#
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
add_executable(ureact_compilation_time_benchmarks EXCLUDE_FROM_ALL)

target_sources(
ureact_compilation_time_benchmarks #
PRIVATE compiler_args.cpp std_headers_include_time.cpp
)

target_link_libraries(
ureact_compilation_time_benchmarks
PRIVATE ureact::ureact Catch2::Catch2WithMain nanobench::nanobench
)

target_compile_options(
ureact_compilation_time_benchmarks
PRIVATE ${UREACT_WARNING_OPTION}
)

get_filename_component(
UREACT_INCLUDE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/../../include"
ABSOLUTE
)
get_filename_component(
TEST_SAMPLES_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/test_samples"
ABSOLUTE
)

target_compile_definitions(
ureact_compilation_time_benchmarks
PRIVATE
UREACT_INCLUDE_PATH="${UREACT_INCLUDE_PATH}"
TEST_SAMPLES_PATH="${TEST_SAMPLES_PATH}"
)
199 changes: 199 additions & 0 deletions tests/compilation_time/compiler_args.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
//
// Copyright (C) 2020-2023 Krylov Yaroslav.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include "compiler_args.hpp"

#include <cassert>
#include <iostream>
#include <sstream>

#include <nanobench.h>

std::ostream& operator<<( std::ostream& os, const BuildConfiguration value )
{
switch( value )
{
case BuildConfiguration::Default: os << "Default"; break;
case BuildConfiguration::Release: os << "Release"; break;
case BuildConfiguration::Debug: os << "Debug"; break;
}
return os;
}

std::ostream& operator<<( std::ostream& os, const CompilerName value )
{
switch( value )
{
case CompilerName::clang: os << "clang++"; break;
case CompilerName::gcc: os << "g++"; break;
}
return os;
}

std::ostream& operator<<( std::ostream& os, const Compiler value )
{
return os << value.name << '-' << value.version;
}

std::string to_string( const Compiler value )
{
std::ostringstream ss;
ss << value;
return ss.str();
}

std::string CompilerArgs::build() const
{
assert( isValid() );
std::ostringstream ss;
ss << m_compiler.value() << ' ';
if( m_standard.has_value() )
ss << "-std=" << m_standard.value() << ' ';
switch( m_configuration.value_or( BuildConfiguration::Default ) )
{
case BuildConfiguration::Debug: ss << "-O0 -g" << ' '; break;
case BuildConfiguration::Release: ss << "-O3" << ' '; break;
case BuildConfiguration::Default: break;
}
ss << "-I" << UREACT_INCLUDE_PATH << ' ';
for( const auto& def : m_definitions )
ss << "-D" << def << ' ';
if( m_stdlib.has_value() )
ss << "-stdlib=" << m_stdlib.value() << ' ';
ss << TEST_SAMPLES_PATH << '/' << m_source.value();
return ss.str();
}

std::string CompilerArgs::get_name() const
{
assert( m_compiler.has_value() );
std::ostringstream ss;
ss << m_compiler.value();
if( m_standard )
ss << ' ' << m_standard.value();
if( m_stdlib )
ss << ' ' << m_stdlib.value();
if( m_configuration )
ss << ' ' << m_configuration.value();
return ss.str();
}

std::vector<CompilerArgs> generateCompilerArgs( const std::vector<Compiler>& compilers,
const std::vector<BuildConfiguration>& configurations,
const int minimalStandard )
{
constexpr bool VERBOSE_ERRORS = false;

std::vector<CompilerArgs> result;

for( const auto& compiler : compilers )
{
if( std::system( ( CompilerArgs{} //
.compiler( to_string( compiler ) )
.source( "minimal.cpp" )
.build()
+ " > /dev/null 2>&1" )
.c_str() )
!= 0 )
{
if constexpr( VERBOSE_ERRORS )
{
std::cerr << "skipping (" << to_string( compiler )
<< ") because it can't compile the simple program" << std::endl;
}
continue;
}

const auto stdlibs = [compiler]() -> std::vector<std::string> {
if( compiler.name == clang )
return { "libstdc++", "libc++" };
else
return { "" };
}();

const auto standards = [compiler, minimalStandard]() -> std::vector<std::string> {
std::vector<std::string> result;
if( minimalStandard <= 11 )
result.emplace_back( "c++11" );
if( minimalStandard <= 14 )
result.emplace_back( "c++14" );
if( minimalStandard <= 17 )
result.emplace_back( "c++17" );
if( minimalStandard <= 20 )
{
if( compiler.name == gcc && compiler.version == 9 )
result.emplace_back( "c++2a" );
else
result.emplace_back( "c++20" );
}
return result;
}();

for( const auto& configuration : configurations )
{
for( const auto& stdlib : stdlibs )
{
if( !stdlib.empty() )
{
if( const auto args = CompilerArgs{} //
.compiler( to_string( compiler ) )
.stdlib( stdlib )
.source( "minimal.cpp" );
std::system( ( args.build() + " > /dev/null 2>&1" ).c_str() ) != 0 )
{
if constexpr( VERBOSE_ERRORS )
{
std::cerr << "skipping (" << args.get_name()
<< ") because it can't compile the simple program"
<< std::endl;
}
continue;
}
}

for( const auto& standard : standards )
{
auto compilerArgs = CompilerArgs{} //
.compiler( to_string( compiler ) )
.standard( standard )
.configuration( configuration );
if( !stdlib.empty() )
compilerArgs.stdlib( stdlib );

if( std::system( ( CompilerArgs{ compilerArgs } //
.source( "minimal.cpp" )
.build()
+ " > /dev/null 2>&1" )
.c_str() )
== 0 )
{
result.push_back( compilerArgs );
}
else
{
if constexpr( VERBOSE_ERRORS )
{
std::cerr << "skipping (" << compilerArgs.get_name()
<< ") because it can't compile the simple program"
<< std::endl;
}
}
}
}
}
}

return result;
}

void perform_test(
ankerl::nanobench::Bench& bench, const std::string& name, const CompilerArgs& compilerArgs )
{
bench.run( name, [&] {
std::system( compilerArgs.build().c_str() ); //
} );
}
112 changes: 112 additions & 0 deletions tests/compilation_time/compiler_args.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//
// Copyright (C) 2020-2023 Krylov Yaroslav.
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once

#include <iosfwd>
#include <optional>
#include <string>
#include <vector>

enum class BuildConfiguration
{
Default,
Release,
Debug
};

std::ostream& operator<<( std::ostream& os, const BuildConfiguration value );

enum class CompilerName
{
clang,
gcc
};

constexpr inline auto clang = CompilerName::clang;
constexpr inline auto gcc = CompilerName::gcc;

std::ostream& operator<<( std::ostream& os, const CompilerName value );

struct Compiler
{
CompilerName name;
int version;
};

std::ostream& operator<<( std::ostream& os, const Compiler value );

std::string to_string( const Compiler value );

class CompilerArgs
{
public:
CompilerArgs& compiler( const std::string& value )
{
m_compiler = value;
return *this;
}

CompilerArgs& standard( const std::string& value )
{
m_standard = value;
return *this;
}

CompilerArgs& configuration( const BuildConfiguration value )
{
m_configuration = value;
return *this;
}

CompilerArgs& source( const std::string& value )
{
m_source = value;
return *this;
}

CompilerArgs& definition( const std::string& value )
{
m_definitions.push_back( value );
return *this;
}

CompilerArgs& stdlib( const std::string& value )
{
m_stdlib = value;
return *this;
}

[[nodiscard]] bool isValid() const
{
return m_compiler.has_value() && m_source.has_value();
}

[[nodiscard]] std::string build() const;

[[nodiscard]] std::string get_name() const;

private:
std::optional<std::string> m_compiler;
std::optional<std::string> m_standard;
std::optional<BuildConfiguration> m_configuration;
std::vector<std::string> m_definitions;
std::optional<std::string> m_stdlib;
std::optional<std::string> m_source;
};

std::vector<CompilerArgs> generateCompilerArgs( const std::vector<Compiler>& compilers,
const std::vector<BuildConfiguration>& configurations,
const int minimalStandard );

namespace ankerl::nanobench
{
class Bench;
}

void perform_test(
ankerl::nanobench::Bench& bench, const std::string& name, const CompilerArgs& compilerArgs );
Loading

0 comments on commit a88ea0e

Please sign in to comment.