<commit_before>/************************************************
 *  static_assoc.hpp
 *  bptree
 *
 *  Copyright (c) 2017, Chi-En Wu
 *  Distributed under MIT License
 ************************************************/

#ifndef BPTREE_INTERNAL_STATIC_ASSOC_HPP_
#define BPTREE_INTERNAL_STATIC_ASSOC_HPP_

#include <cstddef>

#include <algorithm>
#include <type_traits>

#include "./static_vector.hpp"

namespace bptree {

namespace internal {

/************************************************
 * Declaration: class static_assoc<T, U, N>
 ************************************************/

template <typename ValueTraits, bool Unique, std::size_t N>
class static_assoc
  : public ValueTraits,
    private ValueTraits::value_compare {
 private:  // Private Type(s)
    using value_traits = ValueTraits;
    using underlying_type = static_vector<typename value_traits::value_type, N>;

 public:  // Public Type(s)
    using key_type = typename value_traits::key_type;
    using value_type = typename value_traits::value_type;
    using key_compare = typename value_traits::key_compare;
    using value_compare = typename value_traits::value_compare;

    using reference = typename underlying_type::reference;
    using const_reference = typename underlying_type::const_reference;
    using pointer = typename underlying_type::pointer;
    using const_pointer = typename underlying_type::const_pointer;
    using size_type = typename underlying_type::size_type;
    using difference_type = typename underlying_type::difference_type;

    using iterator = typename underlying_type::iterator;
    using const_iterator = typename underlying_type::const_iterator;
    using reverse_iterator = typename underlying_type::reverse_iterator;
    using const_reverse_iterator = typename underlying_type::const_reverse_iterator;

 public:  // Public Method(s)
    static_assoc();
    explicit static_assoc(key_compare comp);
    template <typename InputIt>
    static_assoc(InputIt first, InputIt last, key_compare const& comp = key_compare());
    static_assoc(std::initializer_list<value_type> il, key_compare const& comp = key_compare());
    static_assoc(static_assoc const&) = default;
    static_assoc(static_assoc&&) = default;

    static_assoc& operator=(std::initializer_list<value_type> il);
    static_assoc& operator=(static_assoc const&) = default;
    static_assoc& operator=(static_assoc&&) = default;

    template <typename... Args>
    iterator emplace_hint(const_iterator hint, Args&&... args);
    void clear() noexcept;

    bool empty() const noexcept;
    bool full() const noexcept;
    size_type size() const noexcept;
    constexpr size_type max_size() const noexcept;
    constexpr size_type capacity() const noexcept;

    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    const_iterator cbegin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cend() const noexcept;
    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;
    const_reverse_iterator crend() const noexcept;

    key_compare key_comp() const;
    value_compare value_comp() const;

 private:  // Private Method(s)
    bool is_equal(value_type const& x, value_type const& y);

 private:  // Private Property(ies)
    underlying_type values_;
};

/************************************************
 * Implementation: class static_assoc<T, U, N>
 ************************************************/

template <typename T, bool U, std::size_t N>
inline static_assoc<T, U, N>::static_assoc()
  : static_assoc(key_compare()) {
    // do nothing
}

template <typename T, bool U, std::size_t N>
inline static_assoc<T, U, N>::static_assoc(key_compare comp)
  : value_compare(comp), values_() {
    // do nothing
}

template <typename T, bool U, std::size_t N>
template <typename InputIt>
static_assoc<T, U, N>::static_assoc(InputIt first, InputIt last, key_compare const& comp)
  : static_assoc(comp) {
    while (first != last) {
        auto pos = std::upper_bound(values_.cbegin(), values_.cend(), *first, value_comp());
        if (!U || pos == begin() || !is_equal(*(pos - 1), *first)) {
            values_.insert(pos, *first);
        }

        ++first;
    }
}

template <typename T, bool U, std::size_t N>
inline static_assoc<T, U, N>::static_assoc(std::initializer_list<value_type> il,
                                           key_compare const& comp)
  : static_assoc(il.begin(), il.end(), comp) {
    // do nothing
}

template <typename T, bool U, std::size_t N>
static_assoc<T, U, N>&
static_assoc<T, U, N>::operator=(std::initializer_list<value_type> il) {
    clear();

    for (auto& value : il) {
        auto pos = std::upper_bound(values_.cbegin(), values_.cend(), value, value_comp());
        if (!U || pos == begin() || !is_equal(*(pos - 1), value)) {
            values_.insert(pos, value);
        }
    }

    return *this;
}

template <typename T, bool U, std::size_t N>
template <typename... Args>
typename static_assoc<T, U, N>::iterator
static_assoc<T, U, N>::emplace_hint(const_iterator hint, Args&&... args) {
    value_type value(std::forward<Args>(args)...);
    auto first = cbegin();
    auto last = cend();
    if (hint != first && value_compare::operator()(value, *(hint - 1))) {
        hint = std::upper_bound(first, hint, value, value_comp());
    } else if (hint != last && !value_compare::operator()(value, *hint)) {
        hint = std::upper_bound(hint + 1, last, value, value_comp());
    }

    if (!U || hint == first || value_comp()(*(hint - 1), value)) {
        return values_.insert(hint, std::move(value));
    } else {
        return begin() + (hint - first - 1);
    }
}

template <typename T, bool U, std::size_t N>
inline void static_assoc<T, U, N>::clear() noexcept {
    values_.clear();
}

template <typename T, bool U, std::size_t N>
inline bool static_assoc<T, U, N>::empty() const noexcept {
    return values_.empty();
}

template <typename T, bool U, std::size_t N>
inline bool static_assoc<T, U, N>::full() const noexcept {
    return values_.full();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::size_type
static_assoc<T, U, N>::size() const noexcept {
    return values_.size();
}

template <typename T, bool U, std::size_t N>
inline constexpr typename static_assoc<T, U, N>::size_type
static_assoc<T, U, N>::max_size() const noexcept {
    return values_.max_size();
}

template <typename T, bool U, std::size_t N>
inline constexpr typename static_assoc<T, U, N>::size_type
static_assoc<T, U, N>::capacity() const noexcept {
    return values_.capacity();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::iterator
static_assoc<T, U, N>::begin() noexcept {
    return values_.begin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_iterator
static_assoc<T, U, N>::begin() const noexcept {
    return cbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_iterator
static_assoc<T, U, N>::cbegin() const noexcept {
    return values_.cbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::iterator
static_assoc<T, U, N>::end() noexcept {
    return values_.end();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_iterator
static_assoc<T, U, N>::end() const noexcept {
    return cend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_iterator
static_assoc<T, U, N>::cend() const noexcept {
    return values_.cend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::reverse_iterator
static_assoc<T, U, N>::rbegin() noexcept {
    return values_.rbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_reverse_iterator
static_assoc<T, U, N>::rbegin() const noexcept {
    return crbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_reverse_iterator
static_assoc<T, U, N>::crbegin() const noexcept {
    return values_.crbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::reverse_iterator
static_assoc<T, U, N>::rend() noexcept {
    return values_.rend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_reverse_iterator
static_assoc<T, U, N>::rend() const noexcept {
    return crend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_reverse_iterator
static_assoc<T, U, N>::crend() const noexcept {
    return values_.crend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::key_compare
static_assoc<T, U, N>::key_comp() const {
    return key_compare(*this);
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::value_compare
static_assoc<T, U, N>::value_comp() const {
    return value_compare(*this);
}

template <typename T, bool U, std::size_t N>
inline bool static_assoc<T, U, N>::is_equal(value_type const& x, value_type const& y) {
    return !value_compare::operator()(x, y) && !value_compare::operator()(y, x);
}

}  // namespace internal

}  // namespace bptree

#endif  // BPTREE_INTERNAL_STATIC_ASSOC_HPP_
<commit_msg>:hammer: Implement constructors and assignment operators of `static_assoc` with `static_assoc<>::emplace_hint()`<commit_after>/************************************************
 *  static_assoc.hpp
 *  bptree
 *
 *  Copyright (c) 2017, Chi-En Wu
 *  Distributed under MIT License
 ************************************************/

#ifndef BPTREE_INTERNAL_STATIC_ASSOC_HPP_
#define BPTREE_INTERNAL_STATIC_ASSOC_HPP_

#include <cstddef>

#include <algorithm>
#include <type_traits>

#include "./static_vector.hpp"

namespace bptree {

namespace internal {

/************************************************
 * Declaration: class static_assoc<T, U, N>
 ************************************************/

template <typename ValueTraits, bool Unique, std::size_t N>
class static_assoc
  : public ValueTraits,
    private ValueTraits::value_compare {
 private:  // Private Type(s)
    using value_traits = ValueTraits;
    using underlying_type = static_vector<typename value_traits::value_type, N>;

 public:  // Public Type(s)
    using key_type = typename value_traits::key_type;
    using value_type = typename value_traits::value_type;
    using key_compare = typename value_traits::key_compare;
    using value_compare = typename value_traits::value_compare;

    using reference = typename underlying_type::reference;
    using const_reference = typename underlying_type::const_reference;
    using pointer = typename underlying_type::pointer;
    using const_pointer = typename underlying_type::const_pointer;
    using size_type = typename underlying_type::size_type;
    using difference_type = typename underlying_type::difference_type;

    using iterator = typename underlying_type::iterator;
    using const_iterator = typename underlying_type::const_iterator;
    using reverse_iterator = typename underlying_type::reverse_iterator;
    using const_reverse_iterator = typename underlying_type::const_reverse_iterator;

 public:  // Public Method(s)
    static_assoc();
    explicit static_assoc(key_compare comp);
    template <typename InputIt>
    static_assoc(InputIt first, InputIt last, key_compare const& comp = key_compare());
    static_assoc(std::initializer_list<value_type> il, key_compare const& comp = key_compare());
    static_assoc(static_assoc const&) = default;
    static_assoc(static_assoc&&) = default;

    static_assoc& operator=(std::initializer_list<value_type> il);
    static_assoc& operator=(static_assoc const&) = default;
    static_assoc& operator=(static_assoc&&) = default;

    template <typename... Args>
    iterator emplace_hint(const_iterator hint, Args&&... args);
    void clear() noexcept;

    bool empty() const noexcept;
    bool full() const noexcept;
    size_type size() const noexcept;
    constexpr size_type max_size() const noexcept;
    constexpr size_type capacity() const noexcept;

    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    const_iterator cbegin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cend() const noexcept;
    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;
    const_reverse_iterator crend() const noexcept;

    key_compare key_comp() const;
    value_compare value_comp() const;

 private:  // Private Property(ies)
    underlying_type values_;
};

/************************************************
 * Implementation: class static_assoc<T, U, N>
 ************************************************/

template <typename T, bool U, std::size_t N>
inline static_assoc<T, U, N>::static_assoc()
  : static_assoc(key_compare()) {
    // do nothing
}

template <typename T, bool U, std::size_t N>
inline static_assoc<T, U, N>::static_assoc(key_compare comp)
  : value_compare(comp), values_() {
    // do nothing
}

template <typename T, bool U, std::size_t N>
template <typename InputIt>
static_assoc<T, U, N>::static_assoc(InputIt first, InputIt last, key_compare const& comp)
  : static_assoc(comp) {
    while (first != last) {
        emplace_hint(cend(), *first);
        ++first;
    }
}

template <typename T, bool U, std::size_t N>
inline static_assoc<T, U, N>::static_assoc(std::initializer_list<value_type> il,
                                           key_compare const& comp)
  : static_assoc(il.begin(), il.end(), comp) {
    // do nothing
}

template <typename T, bool U, std::size_t N>
static_assoc<T, U, N>&
static_assoc<T, U, N>::operator=(std::initializer_list<value_type> il) {
    clear();

    for (auto& value : il) {
        emplace_hint(cend(), value);
    }

    return *this;
}

template <typename T, bool U, std::size_t N>
template <typename... Args>
typename static_assoc<T, U, N>::iterator
static_assoc<T, U, N>::emplace_hint(const_iterator hint, Args&&... args) {
    value_type value(std::forward<Args>(args)...);
    auto first = cbegin();
    auto last = cend();
    if (hint != first && value_compare::operator()(value, *(hint - 1))) {
        hint = std::upper_bound(first, hint, value, value_comp());
    } else if (hint != last && !value_compare::operator()(value, *hint)) {
        hint = std::upper_bound(hint + 1, last, value, value_comp());
    }

    if (!U || hint == first || value_comp()(*(hint - 1), value)) {
        return values_.insert(hint, std::move(value));
    } else {
        return begin() + (hint - first - 1);
    }
}

template <typename T, bool U, std::size_t N>
inline void static_assoc<T, U, N>::clear() noexcept {
    values_.clear();
}

template <typename T, bool U, std::size_t N>
inline bool static_assoc<T, U, N>::empty() const noexcept {
    return values_.empty();
}

template <typename T, bool U, std::size_t N>
inline bool static_assoc<T, U, N>::full() const noexcept {
    return values_.full();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::size_type
static_assoc<T, U, N>::size() const noexcept {
    return values_.size();
}

template <typename T, bool U, std::size_t N>
inline constexpr typename static_assoc<T, U, N>::size_type
static_assoc<T, U, N>::max_size() const noexcept {
    return values_.max_size();
}

template <typename T, bool U, std::size_t N>
inline constexpr typename static_assoc<T, U, N>::size_type
static_assoc<T, U, N>::capacity() const noexcept {
    return values_.capacity();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::iterator
static_assoc<T, U, N>::begin() noexcept {
    return values_.begin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_iterator
static_assoc<T, U, N>::begin() const noexcept {
    return cbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_iterator
static_assoc<T, U, N>::cbegin() const noexcept {
    return values_.cbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::iterator
static_assoc<T, U, N>::end() noexcept {
    return values_.end();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_iterator
static_assoc<T, U, N>::end() const noexcept {
    return cend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_iterator
static_assoc<T, U, N>::cend() const noexcept {
    return values_.cend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::reverse_iterator
static_assoc<T, U, N>::rbegin() noexcept {
    return values_.rbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_reverse_iterator
static_assoc<T, U, N>::rbegin() const noexcept {
    return crbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_reverse_iterator
static_assoc<T, U, N>::crbegin() const noexcept {
    return values_.crbegin();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::reverse_iterator
static_assoc<T, U, N>::rend() noexcept {
    return values_.rend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_reverse_iterator
static_assoc<T, U, N>::rend() const noexcept {
    return crend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::const_reverse_iterator
static_assoc<T, U, N>::crend() const noexcept {
    return values_.crend();
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::key_compare
static_assoc<T, U, N>::key_comp() const {
    return key_compare(*this);
}

template <typename T, bool U, std::size_t N>
inline typename static_assoc<T, U, N>::value_compare
static_assoc<T, U, N>::value_comp() const {
    return value_compare(*this);
}

}  // namespace internal

}  // namespace bptree

#endif  // BPTREE_INTERNAL_STATIC_ASSOC_HPP_
<|endoftext|>


<commit_before>#include "CLSmith/StatementComm.h"

#include <algorithm>
#include <ostream>
#include <random>
#include <vector>

#include "Block.h"
#include "CGContext.h"
#include "CLSmith/CLOptions.h"
#include "CLSmith/CLProgramGenerator.h" // temp
#include "CLSmith/ExpressionID.h"
#include "CLSmith/Globals.h"
#include "CLSmith/MemoryBuffer.h"
#include "CLSmith/StatementBarrier.h"
#include "Constant.h"
#include "Expression.h"
#include "ExpressionFuncall.h"
#include "ExpressionVariable.h"
#include "Lhs.h"
#include "SafeOpFlags.h"
#include "StatementAssign.h"
#include "Type.h"
#include "Variable.h"
#include "VariableSelector.h"

namespace CLSmith {
namespace {
// Number of permutations.
const int kPermCount = 10;

// Const buffer that holds the random permutations of [0..31].
MemoryBuffer *permutations;
// Each permutation.
std::vector<int> *permute_values[kPermCount];
// Local buffer that holds the intermediate values.
MemoryBuffer *values;
// Variable that holds the random thread ID.
Variable *tid;
// Variable used in random expressions throughout the program.
MemoryBuffer *var;
}  // namespace

StatementComm *StatementComm::make_random(CGContext& cg_context) {
  int group_size = CLProgramGenerator::get_threads_per_group();
  // rand_expr
  Expression *expr = Expression::make_random(
      cg_context, &Type::get_simple_type(eUInt));
  // rand_expr % 10
  expr = new ExpressionFuncall(*new FunctionInvocationBinary(eMod,
      expr, Constant::make_int(10), SafeOpFlags::make_dummy_flags()));
  // tid % group_size
  Expression *expr_ = new ExpressionFuncall(*new FunctionInvocationBinary(eMod,
      new ExpressionVariable(*tid), Constant::make_int(group_size),
      SafeOpFlags::make_dummy_flags()));
  // permutations[rand_expr % 10][tid % group_size]
  expr = new ExpressionVariable(*permutations->itemize(
      std::vector<const Expression *>({expr, expr_}),
      cg_context.get_current_block()));
  // get_linear_group_id() * group_size
  expr_ = new ExpressionFuncall(*new FunctionInvocationBinary(eMul,
      new ExpressionID(ExpressionID::kLinearGroup),
      Constant::make_int(group_size), SafeOpFlags::make_dummy_flags()));
  // (get_linear_group_id() * group_size) + permutations[rand_expr % 10][tid % group_size]
  expr = new ExpressionFuncall(*new FunctionInvocationBinary(eAdd,
      expr_, expr, SafeOpFlags::make_dummy_flags()));
  // permutations[rand_expr % 10][(get_linear_group_id() * group_size) + tid]
  //expr = new ExpressionVariable(*permutations->itemize(
  //    std::vector<const Expression *>({expr, expr_}),
  //    cg_context.get_current_block()));
  StatementAssign *st_ass = StatementAssign::make_possible_compound_assign(
      cg_context, *new Lhs(*tid), eSimpleAssign, *expr);
  return new StatementComm(cg_context.get_current_block(),
      new StatementBarrier(cg_context.get_current_block()), st_ass);
}

void StatementComm::InitBuffers() {
  unsigned perm_size = CLProgramGenerator::get_threads_per_group();
  for (int idx = 0; idx < kPermCount; ++idx) {
    permute_values[idx] = new std::vector<int>(perm_size);
    for (unsigned id = 0; id < perm_size; ++id) (*permute_values[idx])[id] = id;
    std::shuffle(permute_values[idx]->begin(), permute_values[idx]->end(),
        std::default_random_engine(rnd_upto(65535)));
  }
  permutations = MemoryBuffer::CreateMemoryBuffer(MemoryBuffer::kConst,
      "permutations", &Type::get_simple_type(eUInt), NULL,
      {kPermCount, perm_size});
  values = MemoryBuffer::CreateMemoryBuffer(MemoryBuffer::kGlobal, "comm_values",
      &Type::get_simple_type(eLongLong), Constant::make_int(1),
      {CLProgramGenerator::get_total_threads()});
  // The initial value of the tid will come from the first permutation.
  // Lots of memory leaks here, probably not worth cleaning.
  ExpressionVariable *init = new ExpressionVariable(*permutations->itemize(  // leak
      std::vector<const Expression *>({
      Constant::make_int(0), new ExpressionID(ExpressionID::kLinearLocal)}),
      new Block(NULL, 0)));  // leak
  tid = Variable::CreateVariable("tid", &Type::get_simple_type(eUInt), init,
      new CVQualifiers(std::vector<bool>({false}), std::vector<bool>({false})));
  // The variable that will be accessed throughout the program randomly.
  var = values->itemize(std::vector<const Expression *>({
      new ExpressionVariable(*tid)}), new Block(NULL, 0));  // leak
  if (CLOptions::inter_thread_comm())
    VariableSelector::GetGlobalVariables()->push_back(var);
}

void StatementComm::OutputPermutations(std::ostream& out) {
  permutations->OutputDecl(out);
  out << " = {" << std::endl;
  for (int idx = 0; idx < kPermCount; ++idx) {
    out << "{" << (*permute_values[idx])[0];
    for (int id = 1; id < (int)permute_values[idx]->size(); ++id)
      out << "," << (*permute_values[idx])[id];
    out << "}";
    if (idx < kPermCount - 1) out << ",";
    out << " // permutation " << idx << std::endl;
  }
  out << "};" << std::endl;
}

void StatementComm::AddVarsToGlobals(Globals *globals) {
  assert(values != NULL && tid != NULL);
  globals->AddGlobalMemoryBuffer(values);
  globals->AddGlobalVariable(tid);
}

void StatementComm::HashCommValues(std::ostream& out) {
  assert(values != NULL);
  values->hash(out);
}

void StatementComm::Output(std::ostream& out, FactMgr *fm, int indent) const {
  barrier_->Output(out, fm, indent);
  assign_->Output(out, fm, indent);
}

}  // namespace CLSmith
<commit_msg>Fix macro generations in StatementComm<commit_after>#include "CLSmith/StatementComm.h"

#include <algorithm>
#include <ostream>
#include <random>
#include <vector>

#include "Block.h"
#include "CGContext.h"
#include "CLSmith/CLOptions.h"
#include "CLSmith/CLProgramGenerator.h" // temp
#include "CLSmith/ExpressionID.h"
#include "CLSmith/Globals.h"
#include "CLSmith/MemoryBuffer.h"
#include "CLSmith/StatementBarrier.h"
#include "Constant.h"
#include "Expression.h"
#include "ExpressionFuncall.h"
#include "ExpressionVariable.h"
#include "Lhs.h"
#include "SafeOpFlags.h"
#include "StatementAssign.h"
#include "Type.h"
#include "Variable.h"
#include "VariableSelector.h"

namespace CLSmith {
namespace {
// Number of permutations.
const int kPermCount = 10;

// Const buffer that holds the random permutations of [0..31].
MemoryBuffer *permutations;
// Each permutation.
std::vector<int> *permute_values[kPermCount];
// Local buffer that holds the intermediate values.
MemoryBuffer *values;
// Variable that holds the random thread ID.
Variable *tid;
// Variable used in random expressions throughout the program.
MemoryBuffer *var;
}  // namespace

StatementComm *StatementComm::make_random(CGContext& cg_context) {
  int group_size = CLProgramGenerator::get_threads_per_group();
  // rand_expr
  Expression *expr = Expression::make_random(
      cg_context, &Type::get_simple_type(eUInt));
  // rand_expr % 10
  expr = new ExpressionFuncall(*new FunctionInvocationBinary(eMod, expr,
      Constant::make_int(10), new SafeOpFlags(false, true, true, sInt32)));
  // tid % group_size
  Expression *expr_ = new ExpressionFuncall(*new FunctionInvocationBinary(eMod,
      new ExpressionVariable(*tid), Constant::make_int(group_size),
      new SafeOpFlags(false, false, true, sInt32)));
  // permutations[rand_expr % 10][tid % group_size]
  expr = new ExpressionVariable(*permutations->itemize(
      std::vector<const Expression *>({expr, expr_}),
      cg_context.get_current_block()));
  // get_linear_group_id() * group_size
  expr_ = new ExpressionFuncall(*new FunctionInvocationBinary(eMul,
      new ExpressionID(ExpressionID::kLinearGroup),
      Constant::make_int(group_size),
      new SafeOpFlags(false, false, true, sInt32)));
  // (get_linear_group_id() * group_size) + permutations[rand_expr % 10][tid % group_size]
  expr = new ExpressionFuncall(*new FunctionInvocationBinary(eAdd,
      expr_, expr, new SafeOpFlags(false, false, true, sInt32)));
  StatementAssign *st_ass = StatementAssign::make_possible_compound_assign(
      cg_context, *new Lhs(*tid), eSimpleAssign, *expr);
  return new StatementComm(cg_context.get_current_block(),
      new StatementBarrier(cg_context.get_current_block()), st_ass);
}

void StatementComm::InitBuffers() {
  unsigned perm_size = CLProgramGenerator::get_threads_per_group();
  for (int idx = 0; idx < kPermCount; ++idx) {
    permute_values[idx] = new std::vector<int>(perm_size);
    for (unsigned id = 0; id < perm_size; ++id) (*permute_values[idx])[id] = id;
    std::shuffle(permute_values[idx]->begin(), permute_values[idx]->end(),
        std::default_random_engine(rnd_upto(65535)));
  }
  permutations = MemoryBuffer::CreateMemoryBuffer(MemoryBuffer::kConst,
      "permutations", &Type::get_simple_type(eUInt), NULL,
      {kPermCount, perm_size});
  values = MemoryBuffer::CreateMemoryBuffer(MemoryBuffer::kGlobal, "comm_values",
      &Type::get_simple_type(eLongLong), Constant::make_int(1),
      {CLProgramGenerator::get_total_threads()});
  // The initial value of the tid will come from the first permutation.
  // Lots of memory leaks here, probably not worth cleaning.
  ExpressionVariable *init = new ExpressionVariable(*permutations->itemize(  // leak
      std::vector<const Expression *>({
      Constant::make_int(0), new ExpressionID(ExpressionID::kLinearLocal)}),
      new Block(NULL, 0)));  // leak
  tid = Variable::CreateVariable("tid", &Type::get_simple_type(eUInt), init,
      new CVQualifiers(std::vector<bool>({false}), std::vector<bool>({false})));
  // The variable that will be accessed throughout the program randomly.
  var = values->itemize(std::vector<const Expression *>({
      new ExpressionVariable(*tid)}), new Block(NULL, 0));  // leak
  if (CLOptions::inter_thread_comm())
    VariableSelector::GetGlobalVariables()->push_back(var);
}

void StatementComm::OutputPermutations(std::ostream& out) {
  permutations->OutputDecl(out);
  out << " = {" << std::endl;
  for (int idx = 0; idx < kPermCount; ++idx) {
    out << "{" << (*permute_values[idx])[0];
    for (int id = 1; id < (int)permute_values[idx]->size(); ++id)
      out << "," << (*permute_values[idx])[id];
    out << "}";
    if (idx < kPermCount - 1) out << ",";
    out << " // permutation " << idx << std::endl;
  }
  out << "};" << std::endl;
}

void StatementComm::AddVarsToGlobals(Globals *globals) {
  assert(values != NULL && tid != NULL);
  globals->AddGlobalMemoryBuffer(values);
  globals->AddGlobalVariable(tid);
}

void StatementComm::HashCommValues(std::ostream& out) {
  assert(values != NULL);
  values->hash(out);
}

void StatementComm::Output(std::ostream& out, FactMgr *fm, int indent) const {
  barrier_->Output(out, fm, indent);
  assign_->Output(out, fm, indent);
}

}  // namespace CLSmith
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/oobe_progress_bar.h"

#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia.h"

namespace chromeos {

// static
SkBitmap* OobeProgressBar::dot_current_ = NULL;
SkBitmap* OobeProgressBar::dot_empty_ = NULL;
SkBitmap* OobeProgressBar::dot_filled_ = NULL;
SkBitmap* OobeProgressBar::line_ = NULL;
SkBitmap* OobeProgressBar::line_left_ = NULL;
SkBitmap* OobeProgressBar::line_right_ = NULL;

static const SkColor kCurrentTextColor = SkColorSetRGB(255, 255, 255);
static const SkColor kEmptyTextColor = SkColorSetRGB(112, 115, 118);
static const SkColor kFilledTextColor = SkColorSetRGB(112, 115, 118);
static const int kTextPadding = 5;

OobeProgressBar::OobeProgressBar(const std::vector<int>& steps)
    : steps_(steps), progress_(0) {
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  font_ = rb.GetFont(ResourceBundle::BaseFont);
  InitClass();
}

OobeProgressBar::~OobeProgressBar() {}

// static
void OobeProgressBar::InitClass() {
  static bool initialized = false;
  if (!initialized) {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();

    // Load images.
    dot_current_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_DOT_CURRENT);
    dot_empty_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_DOT_EMPTY);
    dot_filled_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_DOT_FILLED);
    line_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_LINE);
    line_left_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_LINE_LEFT);
    line_right_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_LINE_RIGHT);

    initialized = true;
  }
}

void OobeProgressBar::OnPaint(gfx::Canvas* canvas) {
  gfx::Rect bounds = GetContentsBounds();

  int x = bounds.x();
  int y = bounds.y();

  double step_width = static_cast<double>(bounds.width()) / steps_.size();

  for (size_t i = 0; i < steps_.size(); ++i) {
    SkBitmap* dot;
    SkColor color;
    SkBitmap* line_before = line_;
    SkBitmap* line_after = line_;
    if (i < progress_) {
      dot = dot_filled_;
      color = kFilledTextColor;
    } else if (i == progress_) {
      dot = dot_current_;
      color = kCurrentTextColor;
      line_before = line_left_;
      line_after = line_right_;
    } else {
      dot = dot_empty_;
      color = kEmptyTextColor;
    }

    // x coordinate for next step.
    int next_x = static_cast<int>((i + 1) * step_width);

    // Offset of line origin from dot origin.
    int line_offset_y = (dot->height() - line_->height()) / 2;

    // Current x for painting.
    int ix = x;

    int line_width = ((next_x - x) -
        (line_before->width() + dot->width() + line_after->width())) / 2;
    if (i > 0) {
      canvas->TileImageInt(*line_, ix, y + line_offset_y,
                           line_width, line_->height());
    }
    ix += line_width;
    if (i > 0) {
      canvas->DrawBitmapInt(*line_before, ix, y + line_offset_y);
    }
    ix += line_before->width();

    canvas->DrawBitmapInt(*dot, ix, y);
    ix += dot->width();

    if (i != steps_.size() - 1)
      canvas->DrawBitmapInt(*line_after, ix, y + line_offset_y);
    ix += line_after->width();

    if (i != steps_.size() - 1) {
      canvas->TileImageInt(*line_, ix, y + line_offset_y,
                           next_x - ix, line_->height());
    }

    string16 str = l10n_util::GetStringUTF16(steps_[i]);
    canvas->DrawStringInt(str, font_, color,
        x + kTextPadding, y + dot->height() + kTextPadding,
        (next_x - x - 2 * kTextPadding),
        (bounds.height() - dot->height() - 2 * kTextPadding),
        gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_CENTER |
            gfx::Canvas::TEXT_VALIGN_TOP);

    x = next_x;
  }
}

void OobeProgressBar::OnLocaleChanged() {
  font_ = ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
  SchedulePaint();
}

void OobeProgressBar::SetStep(int step) {
  for (size_t i = 0; i < steps_.size(); ++i) {
    if (steps_[i] == step) {
      progress_ = i;
      SchedulePaint();
      return;
    }
  }
  NOTREACHED();
}

}  // namespace chromeos
<commit_msg>Add NO_ELLIPSIS because TEXT_ALIGN_CENTER doesn't work without it<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/oobe_progress_bar.h"

#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia.h"

namespace chromeos {

// static
SkBitmap* OobeProgressBar::dot_current_ = NULL;
SkBitmap* OobeProgressBar::dot_empty_ = NULL;
SkBitmap* OobeProgressBar::dot_filled_ = NULL;
SkBitmap* OobeProgressBar::line_ = NULL;
SkBitmap* OobeProgressBar::line_left_ = NULL;
SkBitmap* OobeProgressBar::line_right_ = NULL;

static const SkColor kCurrentTextColor = SkColorSetRGB(255, 255, 255);
static const SkColor kEmptyTextColor = SkColorSetRGB(112, 115, 118);
static const SkColor kFilledTextColor = SkColorSetRGB(112, 115, 118);
static const int kTextPadding = 5;

OobeProgressBar::OobeProgressBar(const std::vector<int>& steps)
    : steps_(steps), progress_(0) {
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  font_ = rb.GetFont(ResourceBundle::BaseFont);
  InitClass();
}

OobeProgressBar::~OobeProgressBar() {}

// static
void OobeProgressBar::InitClass() {
  static bool initialized = false;
  if (!initialized) {
    ResourceBundle& rb = ResourceBundle::GetSharedInstance();

    // Load images.
    dot_current_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_DOT_CURRENT);
    dot_empty_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_DOT_EMPTY);
    dot_filled_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_DOT_FILLED);
    line_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_LINE);
    line_left_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_LINE_LEFT);
    line_right_ = rb.GetBitmapNamed(IDR_OOBE_PROGRESS_LINE_RIGHT);

    initialized = true;
  }
}

void OobeProgressBar::OnPaint(gfx::Canvas* canvas) {
  gfx::Rect bounds = GetContentsBounds();

  int x = bounds.x();
  int y = bounds.y();

  double step_width = static_cast<double>(bounds.width()) / steps_.size();

  for (size_t i = 0; i < steps_.size(); ++i) {
    SkBitmap* dot;
    SkColor color;
    SkBitmap* line_before = line_;
    SkBitmap* line_after = line_;
    if (i < progress_) {
      dot = dot_filled_;
      color = kFilledTextColor;
    } else if (i == progress_) {
      dot = dot_current_;
      color = kCurrentTextColor;
      line_before = line_left_;
      line_after = line_right_;
    } else {
      dot = dot_empty_;
      color = kEmptyTextColor;
    }

    // x coordinate for next step.
    int next_x = static_cast<int>((i + 1) * step_width);

    // Offset of line origin from dot origin.
    int line_offset_y = (dot->height() - line_->height()) / 2;

    // Current x for painting.
    int ix = x;

    int line_width = ((next_x - x) -
        (line_before->width() + dot->width() + line_after->width())) / 2;
    if (i > 0) {
      canvas->TileImageInt(*line_, ix, y + line_offset_y,
                           line_width, line_->height());
    }
    ix += line_width;
    if (i > 0) {
      canvas->DrawBitmapInt(*line_before, ix, y + line_offset_y);
    }
    ix += line_before->width();

    canvas->DrawBitmapInt(*dot, ix, y);
    ix += dot->width();

    if (i != steps_.size() - 1)
      canvas->DrawBitmapInt(*line_after, ix, y + line_offset_y);
    ix += line_after->width();

    if (i != steps_.size() - 1) {
      canvas->TileImageInt(*line_, ix, y + line_offset_y,
                           next_x - ix, line_->height());
    }

    string16 str = l10n_util::GetStringUTF16(steps_[i]);
    canvas->DrawStringInt(str, font_, color,
        x + kTextPadding, y + dot->height() + kTextPadding,
        (next_x - x - 2 * kTextPadding),
        (bounds.height() - dot->height() - 2 * kTextPadding),
        gfx::Canvas::MULTI_LINE | gfx::Canvas::TEXT_ALIGN_CENTER |
            gfx::Canvas::TEXT_VALIGN_TOP | gfx::Canvas::NO_ELLIPSIS);

    x = next_x;
  }
}

void OobeProgressBar::OnLocaleChanged() {
  font_ = ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
  SchedulePaint();
}

void OobeProgressBar::SetStep(int step) {
  for (size_t i = 0; i < steps_.size(); ++i) {
    if (steps_[i] == step) {
      progress_ = i;
      SchedulePaint();
      return;
    }
  }
  NOTREACHED();
}

}  // namespace chromeos
<|endoftext|>


<commit_before>//===- ProfileSummaryInfo.cpp - Global profile summary information --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a pass that provides access to the global profile summary
// information.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ProfileSummary.h"
using namespace llvm;

// The following two parameters determine the threshold for a count to be
// considered hot/cold. These two parameters are percentile values (multiplied
// by 10000). If the counts are sorted in descending order, the minimum count to
// reach ProfileSummaryCutoffHot gives the threshold to determine a hot count.
// Similarly, the minimum count to reach ProfileSummaryCutoffCold gives the
// threshold for determining cold count (everything <= this threshold is
// considered cold).

static cl::opt<int> ProfileSummaryCutoffHot(
    "profile-summary-cutoff-hot", cl::Hidden, cl::init(999000), cl::ZeroOrMore,
    cl::desc("A count is hot if it exceeds the minimum count to"
             " reach this percentile of total counts."));

static cl::opt<int> ProfileSummaryCutoffCold(
    "profile-summary-cutoff-cold", cl::Hidden, cl::init(999999), cl::ZeroOrMore,
    cl::desc("A count is cold if it is below the minimum count"
             " to reach this percentile of total counts."));

// Find the minimum count to reach a desired percentile of counts.
static uint64_t getMinCountForPercentile(SummaryEntryVector &DS,
                                         uint64_t Percentile) {
  auto Compare = [](const ProfileSummaryEntry &Entry, uint64_t Percentile) {
    return Entry.Cutoff < Percentile;
  };
  auto It = std::lower_bound(DS.begin(), DS.end(), Percentile, Compare);
  // The required percentile has to be <= one of the percentiles in the
  // detailed summary.
  if (It == DS.end())
    report_fatal_error("Desired percentile exceeds the maximum cutoff");
  return It->MinCount;
}

// The profile summary metadata may be attached either by the frontend or by
// any backend passes (IR level instrumentation, for example). This method
// checks if the Summary is null and if so checks if the summary metadata is now
// available in the module and parses it to get the Summary object. Returns true
// if a valid Summary is available.
bool ProfileSummaryInfo::computeSummary() {
  if (Summary)
    return true;
  auto *SummaryMD = M.getProfileSummary();
  if (!SummaryMD)
    return false;
  Summary.reset(ProfileSummary::getFromMD(SummaryMD));
  return true;
}

/// Returns true if the function's entry is hot. If it returns false, it
/// either means it is not hot or it is unknown whether it is hot or not (for
/// example, no profile data is available).
bool ProfileSummaryInfo::isFunctionEntryHot(const Function *F) {
  if (!F || !computeSummary())
    return false;
  auto FunctionCount = F->getEntryCount();
  // FIXME: The heuristic used below for determining hotness is based on
  // preliminary SPEC tuning for inliner. This will eventually be a
  // convenience method that calls isHotCount.
  return FunctionCount && isHotCount(FunctionCount.getValue());
}

/// Returns true if the function's entry is a cold. If it returns false, it
/// either means it is not cold or it is unknown whether it is cold or not (for
/// example, no profile data is available).
bool ProfileSummaryInfo::isFunctionEntryCold(const Function *F) {
  if (!F)
    return false;
  if (F->hasFnAttribute(Attribute::Cold)) {
    return true;
  }
  if (!computeSummary())
    return false;
  auto FunctionCount = F->getEntryCount();
  // FIXME: The heuristic used below for determining coldness is based on
  // preliminary SPEC tuning for inliner. This will eventually be a
  // convenience method that calls isHotCount.
  return FunctionCount && isColdCount(FunctionCount.getValue());
}

/// Compute the hot and cold thresholds.
void ProfileSummaryInfo::computeThresholds() {
  if (!computeSummary())
    return;
  auto &DetailedSummary = Summary->getDetailedSummary();
  HotCountThreshold =
      getMinCountForPercentile(DetailedSummary, ProfileSummaryCutoffHot);
  ColdCountThreshold =
      getMinCountForPercentile(DetailedSummary, ProfileSummaryCutoffCold);
}

bool ProfileSummaryInfo::isHotCount(uint64_t C) {
  if (!HotCountThreshold)
    computeThresholds();
  return HotCountThreshold && C >= HotCountThreshold.getValue();
}

bool ProfileSummaryInfo::isColdCount(uint64_t C) {
  if (!ColdCountThreshold)
    computeThresholds();
  return ColdCountThreshold && C <= ColdCountThreshold.getValue();
}

bool ProfileSummaryInfo::isHotBB(const BasicBlock *B, BlockFrequencyInfo *BFI) {
  auto Count = BFI->getBlockProfileCount(B);
  if (Count && isHotCount(*Count))
    return true;
  // Use extractProfTotalWeight to get BB count.
  // For Sample PGO, BFI may not provide accurate BB count due to errors
  // magnified during sample count propagation. This serves as a backup plan
  // to ensure all hot BB will not be missed.
  // The query currently has false positives as branch instruction cloning does
  // not update/scale branch weights. Unlike false negatives, this will not cause
  // performance problem.
  uint64_t TotalCount;
  auto *TI = B->getTerminator();
  return extractProfTotalWeight(TI, TotalCount) && isHotCount(TotalCount);
}

bool ProfileSummaryInfo::isColdBB(const BasicBlock *B,
                                  BlockFrequencyInfo *BFI) {
  auto Count = BFI->getBlockProfileCount(B);
  return Count && isColdCount(*Count);
}

bool ProfileSummaryInfo::extractProfTotalWeight(const Instruction *I,
                                                uint64_t &TotalCount) {
  if (!computeSummary())
    return false;
  // Use profile weight on metadata only for sample profiling where block counts
  // could differ from the count of an instruction within the block.
  if (Summary.get()->getKind() != ProfileSummary::PSK_Sample)
    return false;

  return (isa<CallInst>(I) ||
          (isa<TerminatorInst>(I) && !isa<ReturnInst>(I))) &&
         I->extractProfTotalWeight(TotalCount);
}

bool ProfileSummaryInfo::isHotCallSite(const CallSite &CS,
                                       BlockFrequencyInfo *BFI) {
  auto *CallInst = CS.getInstruction();
  if (!CS)
    return false;
  // Check if there is a profile metadata on the instruction. If it is present,
  // determine hotness solely based on that.
  uint64_t TotalCount;
  if (extractProfTotalWeight(CallInst, TotalCount))
    return isHotCount(TotalCount);
  return BFI && isHotBB(CallInst->getParent(), BFI);
}

bool ProfileSummaryInfo::isColdCallSite(const CallSite &CS,
                                        BlockFrequencyInfo *BFI) {
  auto *CallInst = CS.getInstruction();
  if (!CS)
    return false;
  // Check if there is a profile metadata on the instruction. If it is present,
  // and tells that the callsite is not cold, then return false;
  uint64_t TotalCount;
  if (extractProfTotalWeight(CallInst, TotalCount) && !isColdCount(TotalCount))
    return false;
  return BFI && isColdBB(CallInst->getParent(), BFI);
}

INITIALIZE_PASS(ProfileSummaryInfoWrapperPass, "profile-summary-info",
                "Profile summary info", false, true)

ProfileSummaryInfoWrapperPass::ProfileSummaryInfoWrapperPass()
    : ImmutablePass(ID) {
  initializeProfileSummaryInfoWrapperPassPass(*PassRegistry::getPassRegistry());
}

bool ProfileSummaryInfoWrapperPass::doInitialization(Module &M) {
  PSI.reset(new ProfileSummaryInfo(M));
  return false;
}

bool ProfileSummaryInfoWrapperPass::doFinalization(Module &M) {
  PSI.reset();
  return false;
}

AnalysisKey ProfileSummaryAnalysis::Key;
ProfileSummaryInfo ProfileSummaryAnalysis::run(Module &M,
                                               ModuleAnalysisManager &) {
  return ProfileSummaryInfo(M);
}

PreservedAnalyses ProfileSummaryPrinterPass::run(Module &M,
                                                 ModuleAnalysisManager &AM) {
  ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);

  OS << "Functions in " << M.getName() << " with hot/cold annotations: \n";
  for (auto &F : M) {
    OS << F.getName();
    if (PSI.isFunctionEntryHot(&F))
      OS << " :hot entry ";
    else if (PSI.isFunctionEntryCold(&F))
      OS << " :cold entry ";
    OS << "\n";
  }
  return PreservedAnalyses::all();
}

char ProfileSummaryInfoWrapperPass::ID = 0;
<commit_msg>Do not use branch metadata to check if a basic block is hot.<commit_after>//===- ProfileSummaryInfo.cpp - Global profile summary information --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a pass that provides access to the global profile summary
// information.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ProfileSummary.h"
using namespace llvm;

// The following two parameters determine the threshold for a count to be
// considered hot/cold. These two parameters are percentile values (multiplied
// by 10000). If the counts are sorted in descending order, the minimum count to
// reach ProfileSummaryCutoffHot gives the threshold to determine a hot count.
// Similarly, the minimum count to reach ProfileSummaryCutoffCold gives the
// threshold for determining cold count (everything <= this threshold is
// considered cold).

static cl::opt<int> ProfileSummaryCutoffHot(
    "profile-summary-cutoff-hot", cl::Hidden, cl::init(999000), cl::ZeroOrMore,
    cl::desc("A count is hot if it exceeds the minimum count to"
             " reach this percentile of total counts."));

static cl::opt<int> ProfileSummaryCutoffCold(
    "profile-summary-cutoff-cold", cl::Hidden, cl::init(999999), cl::ZeroOrMore,
    cl::desc("A count is cold if it is below the minimum count"
             " to reach this percentile of total counts."));

// Find the minimum count to reach a desired percentile of counts.
static uint64_t getMinCountForPercentile(SummaryEntryVector &DS,
                                         uint64_t Percentile) {
  auto Compare = [](const ProfileSummaryEntry &Entry, uint64_t Percentile) {
    return Entry.Cutoff < Percentile;
  };
  auto It = std::lower_bound(DS.begin(), DS.end(), Percentile, Compare);
  // The required percentile has to be <= one of the percentiles in the
  // detailed summary.
  if (It == DS.end())
    report_fatal_error("Desired percentile exceeds the maximum cutoff");
  return It->MinCount;
}

// The profile summary metadata may be attached either by the frontend or by
// any backend passes (IR level instrumentation, for example). This method
// checks if the Summary is null and if so checks if the summary metadata is now
// available in the module and parses it to get the Summary object. Returns true
// if a valid Summary is available.
bool ProfileSummaryInfo::computeSummary() {
  if (Summary)
    return true;
  auto *SummaryMD = M.getProfileSummary();
  if (!SummaryMD)
    return false;
  Summary.reset(ProfileSummary::getFromMD(SummaryMD));
  return true;
}

/// Returns true if the function's entry is hot. If it returns false, it
/// either means it is not hot or it is unknown whether it is hot or not (for
/// example, no profile data is available).
bool ProfileSummaryInfo::isFunctionEntryHot(const Function *F) {
  if (!F || !computeSummary())
    return false;
  auto FunctionCount = F->getEntryCount();
  // FIXME: The heuristic used below for determining hotness is based on
  // preliminary SPEC tuning for inliner. This will eventually be a
  // convenience method that calls isHotCount.
  return FunctionCount && isHotCount(FunctionCount.getValue());
}

/// Returns true if the function's entry is a cold. If it returns false, it
/// either means it is not cold or it is unknown whether it is cold or not (for
/// example, no profile data is available).
bool ProfileSummaryInfo::isFunctionEntryCold(const Function *F) {
  if (!F)
    return false;
  if (F->hasFnAttribute(Attribute::Cold)) {
    return true;
  }
  if (!computeSummary())
    return false;
  auto FunctionCount = F->getEntryCount();
  // FIXME: The heuristic used below for determining coldness is based on
  // preliminary SPEC tuning for inliner. This will eventually be a
  // convenience method that calls isHotCount.
  return FunctionCount && isColdCount(FunctionCount.getValue());
}

/// Compute the hot and cold thresholds.
void ProfileSummaryInfo::computeThresholds() {
  if (!computeSummary())
    return;
  auto &DetailedSummary = Summary->getDetailedSummary();
  HotCountThreshold =
      getMinCountForPercentile(DetailedSummary, ProfileSummaryCutoffHot);
  ColdCountThreshold =
      getMinCountForPercentile(DetailedSummary, ProfileSummaryCutoffCold);
}

bool ProfileSummaryInfo::isHotCount(uint64_t C) {
  if (!HotCountThreshold)
    computeThresholds();
  return HotCountThreshold && C >= HotCountThreshold.getValue();
}

bool ProfileSummaryInfo::isColdCount(uint64_t C) {
  if (!ColdCountThreshold)
    computeThresholds();
  return ColdCountThreshold && C <= ColdCountThreshold.getValue();
}

bool ProfileSummaryInfo::isHotBB(const BasicBlock *B, BlockFrequencyInfo *BFI) {
  auto Count = BFI->getBlockProfileCount(B);
  return Count && isHotCount(*Count);
}

bool ProfileSummaryInfo::isColdBB(const BasicBlock *B,
                                  BlockFrequencyInfo *BFI) {
  auto Count = BFI->getBlockProfileCount(B);
  return Count && isColdCount(*Count);
}

bool ProfileSummaryInfo::extractProfTotalWeight(const Instruction *I,
                                                uint64_t &TotalCount) {
  if (!computeSummary())
    return false;
  // Use profile weight on metadata only for sample profiling where block counts
  // could differ from the count of an instruction within the block.
  if (Summary.get()->getKind() != ProfileSummary::PSK_Sample)
    return false;

  return (isa<CallInst>(I) ||
          (isa<TerminatorInst>(I) && !isa<ReturnInst>(I))) &&
         I->extractProfTotalWeight(TotalCount);
}

bool ProfileSummaryInfo::isHotCallSite(const CallSite &CS,
                                       BlockFrequencyInfo *BFI) {
  auto *CallInst = CS.getInstruction();
  if (!CS)
    return false;
  // Check if there is a profile metadata on the instruction. If it is present,
  // determine hotness solely based on that.
  uint64_t TotalCount;
  if (extractProfTotalWeight(CallInst, TotalCount))
    return isHotCount(TotalCount);
  return BFI && isHotBB(CallInst->getParent(), BFI);
}

bool ProfileSummaryInfo::isColdCallSite(const CallSite &CS,
                                        BlockFrequencyInfo *BFI) {
  auto *CallInst = CS.getInstruction();
  if (!CS)
    return false;
  // Check if there is a profile metadata on the instruction. If it is present,
  // and tells that the callsite is not cold, then return false;
  uint64_t TotalCount;
  if (extractProfTotalWeight(CallInst, TotalCount) && !isColdCount(TotalCount))
    return false;
  return BFI && isColdBB(CallInst->getParent(), BFI);
}

INITIALIZE_PASS(ProfileSummaryInfoWrapperPass, "profile-summary-info",
                "Profile summary info", false, true)

ProfileSummaryInfoWrapperPass::ProfileSummaryInfoWrapperPass()
    : ImmutablePass(ID) {
  initializeProfileSummaryInfoWrapperPassPass(*PassRegistry::getPassRegistry());
}

bool ProfileSummaryInfoWrapperPass::doInitialization(Module &M) {
  PSI.reset(new ProfileSummaryInfo(M));
  return false;
}

bool ProfileSummaryInfoWrapperPass::doFinalization(Module &M) {
  PSI.reset();
  return false;
}

AnalysisKey ProfileSummaryAnalysis::Key;
ProfileSummaryInfo ProfileSummaryAnalysis::run(Module &M,
                                               ModuleAnalysisManager &) {
  return ProfileSummaryInfo(M);
}

PreservedAnalyses ProfileSummaryPrinterPass::run(Module &M,
                                                 ModuleAnalysisManager &AM) {
  ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);

  OS << "Functions in " << M.getName() << " with hot/cold annotations: \n";
  for (auto &F : M) {
    OS << F.getName();
    if (PSI.isFunctionEntryHot(&F))
      OS << " :hot entry ";
    else if (PSI.isFunctionEntryCold(&F))
      OS << " :cold entry ";
    OS << "\n";
  }
  return PreservedAnalyses::all();
}

char ProfileSummaryInfoWrapperPass::ID = 0;
<|endoftext|>


<commit_before>// Facilitymodel.cc
// Implements the FacilityModel class

#include "facility_model.h"

#include "timer.h"
#include "query_engine.h"
#include "inst_model.h"
#include "error.h"

#include <stdlib.h>
#include <sstream>
#include "logger.h"
#include <limits>

namespace cyclus {

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FacilityModel::FacilityModel(Context* ctx)
    : TimeAgent(ctx),
      fac_lifetime_(std::numeric_limits<int>::max()),
      decommission_date_(std::numeric_limits<int>::max()),
      build_date_(0) {
  SetModelType("Facility");
  in_commods_ = std::vector<std::string>();
  out_commods_ = std::vector<std::string>();
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FacilityModel::~FacilityModel() {};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::InitCoreMembers(QueryEngine* qe) {
  Model::InitCoreMembers(qe);

  // get lifetime
  int lifetime = GetOptionalQuery<int>(qe, "lifetime", context()->sim_dur());
  SetFacLifetime(lifetime);

  // get the incommodities
  std::string commod;
  int numInCommod = qe->NElementsMatchingQuery("incommodity");
  for (int i = 0; i < numInCommod; i++) {
    commod = qe->GetElementContent("incommodity", i);
    in_commods_.push_back(commod);
    LOG(LEV_DEBUG2, "none!") << "Facility " << ID()
                             << " has just added incommodity" << commod;
  }

  // get the outcommodities
  int numOutCommod = qe->NElementsMatchingQuery("outcommodity");
  for (int i = 0; i < numOutCommod; i++) {
    commod = qe->GetElementContent("outcommodity", i);
    out_commods_.push_back(commod);
    LOG(LEV_DEBUG2, "none!") << "Facility " << ID()
                             << " has just added outcommodity" << commod;
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Prototype* FacilityModel::clone() {
  FacilityModel* clone = dynamic_cast<FacilityModel*>(Model::ConstructModel(
                                                        context(),
                                                        ModelImpl()));
  clone->CloneCoreMembersFrom(this);
  clone->CloneModuleMembersFrom(this);
  clone->SetBuildDate(context()->time());
  CLOG(LEV_DEBUG3) << clone->ModelImpl() << " cloned: " << clone->str();
  CLOG(LEV_DEBUG3) << "               From: " << this->str();
  return clone;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::CloneCoreMembersFrom(FacilityModel* source) {
  SetName(source->name());
  SetModelImpl(source->ModelImpl());
  SetModelType(source->ModelType());
  SetFacLifetime(source->FacLifetime());
  in_commods_ = source->InputCommodities();
  out_commods_ = source->OutputCommodities();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string FacilityModel::str() {
  std::stringstream ss("");
  ss << Model::str() << " with: "
     << " lifetime: " << FacLifetime()
     << " build date: " << build_date_
     << " decommission date: " << decommission_date_;
  return ss.str();
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InstModel* FacilityModel::FacInst() {
  return dynamic_cast<InstModel*>(parent());
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::HandleDailyTasks(int time, int day) {
  // facilities who have more intricate details should utilize this function
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::Decommission() {
  if (!CheckDecommissionCondition()) {
    throw Error("Cannot decommission " + name());
  }

  CLOG(LEV_INFO3) << name() << " is being decommissioned";
  DeleteModel(this);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FacilityModel::CheckDecommissionCondition() {
  return true;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::vector<std::string> FacilityModel::InputCommodities() {
  return in_commods_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::vector<std::string> FacilityModel::OutputCommodities() {
  return out_commods_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FacilityModel::LifetimeReached(int time) {
  return (time >= decommission_date_);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::SetBuildDate(int current_time) {
  build_date_ = current_time;
  SetDecommissionDate(build_date_ + fac_lifetime_ -
                      1); // -1 because you want the decommission to occur on the previous time's tock
  CLOG(LEV_DEBUG3) << name() << " has set its time-related members: ";
  CLOG(LEV_DEBUG3) << " * lifetime: " << fac_lifetime_;
  CLOG(LEV_DEBUG3) << " * build date: " << build_date_;
  CLOG(LEV_DEBUG3) << " * decommisison date: " << decommission_date_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::SetDecommissionDate(int time) {
  double final_time = context()->start_time() + context()->sim_dur();
  if (time < final_time) {
    decommission_date_ = time;
  } else {
    decommission_date_ = final_time;
  }
  CLOG(LEV_DEBUG3) << name() << " is setting its decommission date: ";
  CLOG(LEV_DEBUG3) << " * Set Time: " << time;
  CLOG(LEV_DEBUG3) << " * Final Time: " << final_time;
  CLOG(LEV_DEBUG3) << " * decommisison date: " << decommission_date_;
}
} // namespace cyclus
<commit_msg>added cyclus namespace qualifier to new function usage<commit_after>// Facilitymodel.cc
// Implements the FacilityModel class

#include "facility_model.h"

#include "timer.h"
#include "query_engine.h"
#include "inst_model.h"
#include "error.h"

#include <stdlib.h>
#include <sstream>
#include "logger.h"
#include <limits>

namespace cyclus {

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FacilityModel::FacilityModel(Context* ctx)
    : TimeAgent(ctx),
      fac_lifetime_(std::numeric_limits<int>::max()),
      decommission_date_(std::numeric_limits<int>::max()),
      build_date_(0) {
  SetModelType("Facility");
  in_commods_ = std::vector<std::string>();
  out_commods_ = std::vector<std::string>();
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FacilityModel::~FacilityModel() {};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::InitCoreMembers(QueryEngine* qe) {
  Model::InitCoreMembers(qe);

  // get lifetime
  int lifetime =
      cyclus::GetOptionalQuery<int>(qe, "lifetime", context()->sim_dur());
  SetFacLifetime(lifetime);

  // get the incommodities
  std::string commod;
  int numInCommod = qe->NElementsMatchingQuery("incommodity");
  for (int i = 0; i < numInCommod; i++) {
    commod = qe->GetElementContent("incommodity", i);
    in_commods_.push_back(commod);
    LOG(LEV_DEBUG2, "none!") << "Facility " << ID()
                             << " has just added incommodity" << commod;
  }

  // get the outcommodities
  int numOutCommod = qe->NElementsMatchingQuery("outcommodity");
  for (int i = 0; i < numOutCommod; i++) {
    commod = qe->GetElementContent("outcommodity", i);
    out_commods_.push_back(commod);
    LOG(LEV_DEBUG2, "none!") << "Facility " << ID()
                             << " has just added outcommodity" << commod;
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Prototype* FacilityModel::clone() {
  FacilityModel* clone = dynamic_cast<FacilityModel*>(Model::ConstructModel(
                                                        context(),
                                                        ModelImpl()));
  clone->CloneCoreMembersFrom(this);
  clone->CloneModuleMembersFrom(this);
  clone->SetBuildDate(context()->time());
  CLOG(LEV_DEBUG3) << clone->ModelImpl() << " cloned: " << clone->str();
  CLOG(LEV_DEBUG3) << "               From: " << this->str();
  return clone;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::CloneCoreMembersFrom(FacilityModel* source) {
  SetName(source->name());
  SetModelImpl(source->ModelImpl());
  SetModelType(source->ModelType());
  SetFacLifetime(source->FacLifetime());
  in_commods_ = source->InputCommodities();
  out_commods_ = source->OutputCommodities();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string FacilityModel::str() {
  std::stringstream ss("");
  ss << Model::str() << " with: "
     << " lifetime: " << FacLifetime()
     << " build date: " << build_date_
     << " decommission date: " << decommission_date_;
  return ss.str();
};

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InstModel* FacilityModel::FacInst() {
  return dynamic_cast<InstModel*>(parent());
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::HandleDailyTasks(int time, int day) {
  // facilities who have more intricate details should utilize this function
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::Decommission() {
  if (!CheckDecommissionCondition()) {
    throw Error("Cannot decommission " + name());
  }

  CLOG(LEV_INFO3) << name() << " is being decommissioned";
  DeleteModel(this);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FacilityModel::CheckDecommissionCondition() {
  return true;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::vector<std::string> FacilityModel::InputCommodities() {
  return in_commods_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::vector<std::string> FacilityModel::OutputCommodities() {
  return out_commods_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FacilityModel::LifetimeReached(int time) {
  return (time >= decommission_date_);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::SetBuildDate(int current_time) {
  build_date_ = current_time;
  SetDecommissionDate(build_date_ + fac_lifetime_ -
                      1); // -1 because you want the decommission to occur on the previous time's tock
  CLOG(LEV_DEBUG3) << name() << " has set its time-related members: ";
  CLOG(LEV_DEBUG3) << " * lifetime: " << fac_lifetime_;
  CLOG(LEV_DEBUG3) << " * build date: " << build_date_;
  CLOG(LEV_DEBUG3) << " * decommisison date: " << decommission_date_;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FacilityModel::SetDecommissionDate(int time) {
  double final_time = context()->start_time() + context()->sim_dur();
  if (time < final_time) {
    decommission_date_ = time;
  } else {
    decommission_date_ = final_time;
  }
  CLOG(LEV_DEBUG3) << name() << " is setting its decommission date: ";
  CLOG(LEV_DEBUG3) << " * Set Time: " << time;
  CLOG(LEV_DEBUG3) << " * Final Time: " << final_time;
  CLOG(LEV_DEBUG3) << " * decommisison date: " << decommission_date_;
}
} // namespace cyclus
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <cassert>

#include <glog/logging.h>
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>

#include "cnetlink.h"
#include "nl_output.h"
#include "nl_vlan.h"
#include "sai.h"

namespace basebox {

nl_vlan::nl_vlan(cnetlink *nl) : swi(nullptr), nl(nl) {}

int nl_vlan::add_vlan(rtnl_link *link, uint16_t vid, bool tagged) {
  assert(swi);

  VLOG(2) << __FUNCTION__ << ": add vid=" << vid << " tagged=" << tagged;
  if (!is_vid_valid(vid)) {
    LOG(ERROR) << __FUNCTION__ << ": invalid vid " << vid;
    return -EINVAL;
  }

  uint32_t port_id = nl->get_port_id(link);

  if (port_id == 0) {
    VLOG(1) << __FUNCTION__ << ": unknown interface " << OBJ_CAST(link);
    return -EINVAL;
  }

  int rv =
      swi->ingress_port_vlan_add(port_id, vid, !tagged /* pvid == !tagged */);
  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__
               << ": failed to setup ingress vlan 1 (untagged) on port_id="
               << port_id << "; rv=" << rv;
    return rv;
  }

  // setup egress interface
  rv = swi->egress_port_vlan_add(port_id, vid, !tagged);

  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__
               << ": failed to setup egress vlan 1 (untagged) on port_id="
               << port_id << "; rv=" << rv;
    (void)swi->ingress_port_vlan_remove(port_id, 1, true);

    return rv;
  }

  auto key = std::make_pair(port_id, vid);
  auto refcount = port_vlan.find(key);
  if (refcount == port_vlan.end()) {
    port_vlan.emplace(key, 1);
  } else
    refcount->second++;

  return rv;
}

int nl_vlan::remove_vlan(rtnl_link *link, uint16_t vid, bool tagged) {
  assert(swi);

  if (!is_vid_valid(vid)) {
    LOG(ERROR) << __FUNCTION__ << ": invalid vid " << vid;
    return -EINVAL;
  }

  int rv = 0;

  uint32_t port_id = nl->get_port_id(link);

  if (port_id == 0) {
    VLOG(1) << __FUNCTION__ << ": unknown link " << OBJ_CAST(link);
    return -EINVAL;
  }

  // check for refcount
  auto key = std::make_pair(port_id, vid);
  auto refcount = port_vlan.find(key);
  if (refcount != port_vlan.end()){
    refcount->second--;
    return rv;
  } else if (refcount->second == 1)
    port_vlan.erase(refcount);

  // remove vid at ingress
  rv = swi->ingress_port_vlan_remove(port_id, vid, !tagged);

  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__ << ": failed with rv=" << rv
               << " to remove vid=" << vid << "(tagged=" << tagged
               << ") of link " << OBJ_CAST(link);
    return rv;
  }

  // delete all FM pointing to this group first
  rv = swi->l2_addr_remove_all_in_vlan(port_id, vid);

  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__ << ": failed with rv= " << rv
               << " to remove all bridge entries in vid=" << vid << " link "
               << OBJ_CAST(link);
    return rv;
  }

  // remove vid from egress
  rv = swi->egress_bridge_port_vlan_remove(port_id, vid);

  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__ << ": failed with rv= " << rv
               << " to remove vid=" << vid << " of link " << OBJ_CAST(link);
    return rv;
  }

  return rv;
}

uint16_t nl_vlan::get_vid(rtnl_link *link) {
  uint16_t vid = 0;
  uint32_t pport_id = nl->get_port_id(link);
  auto lt = get_link_type(link);

  if (pport_id == 0)
    return 0;

  switch (lt) {
  case LT_BRIDGE:
    VLOG(2) << __FUNCTION__ << ": bridge default vid " << default_vid;
    vid = default_vid;
    break;
  case LT_TUN:
  case LT_BOND:
    vid = default_vid;
    break;
  case LT_VLAN:
    vid = rtnl_link_vlan_get_id(link);
    break;
  default:
    if (rtnl_link_get_ifindex(link) != 1)
      LOG(ERROR) << __FUNCTION__ << ": unsupported link type " << lt
                 << " of link " << OBJ_CAST(link);
    break;
  }

  return vid;
}

} // namespace basebox
<commit_msg>ci: fix style check<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <cassert>

#include <glog/logging.h>
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>

#include "cnetlink.h"
#include "nl_output.h"
#include "nl_vlan.h"
#include "sai.h"

namespace basebox {

nl_vlan::nl_vlan(cnetlink *nl) : swi(nullptr), nl(nl) {}

int nl_vlan::add_vlan(rtnl_link *link, uint16_t vid, bool tagged) {
  assert(swi);

  VLOG(2) << __FUNCTION__ << ": add vid=" << vid << " tagged=" << tagged;
  if (!is_vid_valid(vid)) {
    LOG(ERROR) << __FUNCTION__ << ": invalid vid " << vid;
    return -EINVAL;
  }

  uint32_t port_id = nl->get_port_id(link);

  if (port_id == 0) {
    VLOG(1) << __FUNCTION__ << ": unknown interface " << OBJ_CAST(link);
    return -EINVAL;
  }

  int rv =
      swi->ingress_port_vlan_add(port_id, vid, !tagged /* pvid == !tagged */);
  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__
               << ": failed to setup ingress vlan 1 (untagged) on port_id="
               << port_id << "; rv=" << rv;
    return rv;
  }

  // setup egress interface
  rv = swi->egress_port_vlan_add(port_id, vid, !tagged);

  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__
               << ": failed to setup egress vlan 1 (untagged) on port_id="
               << port_id << "; rv=" << rv;
    (void)swi->ingress_port_vlan_remove(port_id, 1, true);

    return rv;
  }

  auto key = std::make_pair(port_id, vid);
  auto refcount = port_vlan.find(key);
  if (refcount == port_vlan.end()) {
    port_vlan.emplace(key, 1);
  } else
    refcount->second++;

  return rv;
}

int nl_vlan::remove_vlan(rtnl_link *link, uint16_t vid, bool tagged) {
  assert(swi);

  if (!is_vid_valid(vid)) {
    LOG(ERROR) << __FUNCTION__ << ": invalid vid " << vid;
    return -EINVAL;
  }

  int rv = 0;

  uint32_t port_id = nl->get_port_id(link);

  if (port_id == 0) {
    VLOG(1) << __FUNCTION__ << ": unknown link " << OBJ_CAST(link);
    return -EINVAL;
  }

  // check for refcount
  auto key = std::make_pair(port_id, vid);
  auto refcount = port_vlan.find(key);
  if (refcount != port_vlan.end()) {
    refcount->second--;
    return rv;
  } else if (refcount->second == 1)
    port_vlan.erase(refcount);

  // remove vid at ingress
  rv = swi->ingress_port_vlan_remove(port_id, vid, !tagged);

  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__ << ": failed with rv=" << rv
               << " to remove vid=" << vid << "(tagged=" << tagged
               << ") of link " << OBJ_CAST(link);
    return rv;
  }

  // delete all FM pointing to this group first
  rv = swi->l2_addr_remove_all_in_vlan(port_id, vid);

  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__ << ": failed with rv= " << rv
               << " to remove all bridge entries in vid=" << vid << " link "
               << OBJ_CAST(link);
    return rv;
  }

  // remove vid from egress
  rv = swi->egress_bridge_port_vlan_remove(port_id, vid);

  if (rv < 0) {
    LOG(ERROR) << __FUNCTION__ << ": failed with rv= " << rv
               << " to remove vid=" << vid << " of link " << OBJ_CAST(link);
    return rv;
  }

  return rv;
}

uint16_t nl_vlan::get_vid(rtnl_link *link) {
  uint16_t vid = 0;
  uint32_t pport_id = nl->get_port_id(link);
  auto lt = get_link_type(link);

  if (pport_id == 0)
    return 0;

  switch (lt) {
  case LT_BRIDGE:
    VLOG(2) << __FUNCTION__ << ": bridge default vid " << default_vid;
    vid = default_vid;
    break;
  case LT_TUN:
  case LT_BOND:
    vid = default_vid;
    break;
  case LT_VLAN:
    vid = rtnl_link_vlan_get_id(link);
    break;
  default:
    if (rtnl_link_get_ifindex(link) != 1)
      LOG(ERROR) << __FUNCTION__ << ": unsupported link type " << lt
                 << " of link " << OBJ_CAST(link);
    break;
  }

  return vid;
}

} // namespace basebox
<|endoftext|>


<commit_before>/* Copyright (C) 2013 Slawomir Cygan <slawomir.cygan@gmail.com>
*
* 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 "gl-types.h"

#include<map>
#include<set>
#include<sstream>

namespace {
#define FUNC_LIST_ELEM_SUPPORTED(name, type, library) #name,
#define FUNC_LIST_ELEM_NOT_SUPPORTED(name, type, library) FUNC_LIST_ELEM_SUPPORTED(name, type, library)
    const char* g_EntrypointNames[] = {
#include "codegen/functionList.inl"
        "<unknown>"
    };
#undef FUNC_LIST_ELEM_SUPPORTED
#undef FUNC_LIST_ELEM_NOT_SUPPORTED

#define ENUM_LIST_ELEMENT(value) {#value, value},
    struct GLEnum {
        const char* name;
        gl_t value;
    }  g_GLEnums[] = {
#include "codegen/enum.inl"
        { NULL, 0 }
    };
#undef ENUM_LIST_ELEMENT

    std::map<std::string, Entrypoint> g_EntryPointNameToEnum;
    std::map<gl_t, std::string> g_GLEnumValueToName;

    void ensureEnumMapIntialized() {
        if (!g_EntryPointNameToEnum.size()) {
            for (Entrypoint e = 0; e < Entrypoints_NUM; e++) {
                g_EntryPointNameToEnum[GetEntryPointName(e)] = e;
            }
        }
        if (!g_GLEnumValueToName.size()) {
            int i = 0;
            while (g_GLEnums[i].name) {
                if (g_GLEnumValueToName.find(g_GLEnums[i].value) == g_GLEnumValueToName.end())
                    //do not overwrite any enum that already exist in the map:
                    //the first come GLenums are "older" - were defined earlier in OGL history.
                    //the duplicates are usually some vendor extensions from the bottom glext.h
                    g_GLEnumValueToName[g_GLEnums[i].value] = g_GLEnums[i].name;
                i++;
            }
        }
    }
}

const char* GetEntryPointName(Entrypoint entryp) {
    return g_EntrypointNames[entryp];
}

Entrypoint GetEntryPointEnum(const char* name) {
    ensureEnumMapIntialized();
    std::map<std::string, Entrypoint>::iterator ret = g_EntryPointNameToEnum.find(name);
    if (ret == g_EntryPointNameToEnum.end())
        return NO_ENTRYPOINT;
    return ret->second;
}

std::string GetGLEnumName(gl_t glEnum) {
    ensureEnumMapIntialized();
    std::map<gl_t, std::string>::iterator ret = g_GLEnumValueToName.find(glEnum);
    if (ret == g_GLEnumValueToName.end()) {
        std::ostringstream tmp;
        tmp << "0x" << std::hex << glEnum;
        return tmp.str();
    }
    return ret->second;
}

std::string GetShaderStageName(gl_t glEnum) {
    switch (glEnum) {
        case GL_VERTEX_SHADER:
            return "Vertex";
        case GL_TESS_CONTROL_SHADER:
            return "Tesselation Control";
        case GL_TESS_EVALUATION_SHADER:
            return "Tesselation Evaluation";
        case GL_GEOMETRY_SHADER:
            return "Geometry";
        case GL_FRAGMENT_SHADER:
            return "Fragment";
        case GL_COMPUTE_SHADER:
            return "Compute";
        default:
            return GetGLEnumName(glEnum).c_str();
    }
}

std::string GetTextureTargetName(gl_t glEnum) {
    switch (glEnum) {
    case GL_TEXTURE_1D:
        return "1D";
    case GL_TEXTURE_2D:
        return "2D";
    case GL_TEXTURE_3D:
        return "3D";
    case GL_TEXTURE_1D_ARRAY:
        return "1D Array";
    case GL_TEXTURE_2D_ARRAY:
        return "2D Array";
    case GL_TEXTURE_RECTANGLE:
        return "Rectangle";
    case GL_TEXTURE_CUBE_MAP:
        return "Cube Map";
    case GL_TEXTURE_CUBE_MAP_ARRAY:
        return "Cube Map Array";
    case GL_TEXTURE_BUFFER:
        return "Buffer";
    case GL_TEXTURE_2D_MULTISAMPLE:
        return "2D MS";
    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
        return "2D MS Array";
    default:
        return GetGLEnumName(glEnum).c_str();
    }
}

namespace call_sets {
    Entrypoint frameDelims[] = {
         wglSwapBuffers_Call,
         wglSwapLayerBuffers_Call,
         wglSwapMultipleBuffers_Call,
         eglSwapBuffers_Call,
         glXSwapBuffers_Call
    };
    Entrypoint drawCalls[] = {
        glDrawElements_Call,
        glDrawElementsBaseVertex_Call,
        glDrawElementsIndirect_Call,
        glDrawElementsInstanced_Call,
        glDrawElementsInstancedARB_Call,
        glDrawElementsInstancedBaseInstance_Call,
        glDrawElementsInstancedBaseVertex_Call,
        glDrawElementsInstancedBaseVertexBaseInstance_Call,
        glDrawElementsInstancedEXT_Call,
        glMultiDrawElements_Call,
        glMultiDrawElementsBaseVertex_Call,
        glMultiDrawElementsEXT_Call,
        glMultiDrawElementsIndirect_Call,
        glMultiDrawElementsIndirectAMD_Call,
        glMultiModeDrawElementsIBM_Call,
        glDrawArrays_Call,
        glDrawArraysEXT_Call,
        glDrawArraysIndirect_Call,
        glDrawArraysInstanced_Call,
        glDrawArraysInstancedARB_Call,
        glDrawArraysInstancedBaseInstance_Call,
        glDrawArraysInstancedEXT_Call,
        glMultiDrawArrays_Call,
        glMultiDrawArraysEXT_Call,
        glMultiDrawArraysIndirect_Call,
        glMultiDrawArraysIndirectAMD_Call,
        glMultiModeDrawArraysIBM_Call,
        glClear_Call,
        glClearBufferfi_Call,
        glClearBufferfv_Call,
        glClearBufferiv_Call,
        glClearBufferuiv_Call,
        glDrawRangeElementArrayAPPLE_Call,
        glDrawRangeElementArrayATI_Call,
        glDrawRangeElements_Call,
        glDrawRangeElementsBaseVertex_Call,
        glDrawRangeElementsEXT_Call,
        glMultiDrawRangeElementArrayAPPLE_Call,
        glEnd_Call,
    };

    std::set<Entrypoint> drawCallSet(&drawCalls[0], &drawCalls[sizeof(drawCalls)/sizeof(drawCalls[0])]);
    std::set<Entrypoint> frameDelimsSet(&frameDelims[0], &frameDelims[sizeof(frameDelims)/sizeof(frameDelims[0])]);
}

bool IsDrawCall(Entrypoint entryp) {
    return call_sets::drawCallSet.find(entryp) != call_sets::drawCallSet.end();
}

bool IsFrameDelimiter(Entrypoint entryp) {
    return call_sets::frameDelimsSet.find(entryp) != call_sets::frameDelimsSet.end();
}
<commit_msg>Allow GetEntryPointEnum usage before static ctors fire in gl-types.cpp. This is needed for dlsym interception to work<commit_after>/* Copyright (C) 2013 Slawomir Cygan <slawomir.cygan@gmail.com>
*
* 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<cstdio>

#include "gl-types.h"

#include<map>
#include<set>
#include<sstream>

namespace lists {
#define FUNC_LIST_ELEM_SUPPORTED(name, type, library) #name,
#define FUNC_LIST_ELEM_NOT_SUPPORTED(name, type, library) FUNC_LIST_ELEM_SUPPORTED(name, type, library)
    const char* g_EntrypointNames[] = {
#include "codegen/functionList.inl"
        "<unknown>"
    };
#undef FUNC_LIST_ELEM_SUPPORTED
#undef FUNC_LIST_ELEM_NOT_SUPPORTED

#define ENUM_LIST_ELEMENT(value) {#value, value},
    struct GLEnum {
        const char* name;
        gl_t value;
    }  g_GLEnums[] = {
#include "codegen/enum.inl"
        { NULL, 0 }
    };
#undef ENUM_LIST_ELEMENT

    struct MapCache {
        MapCache() {

            for (Entrypoint e = 0; e < Entrypoints_NUM; e++) {
                entryPointNameToEnum[GetEntryPointName(e)] = e;
            }

            int i = 0;
            while (g_GLEnums[i].name) {
                if (EnumGLToName.find(g_GLEnums[i].value) == EnumGLToName.end())
                    //do not overwrite any enum that already exist in the map:
                    //the first come GLenums are "older" - were defined earlier in OGL history.
                    //the duplicates are usually some vendor extensions from the bottom glext.h
                    EnumGLToName[g_GLEnums[i].value] = g_GLEnums[i].name;
                i++;
            }
        }

        static MapCache* get() {
            if (!s_cache) {
                s_cache = new MapCache();
            }
            return s_cache;
        }

        static MapCache* s_cache;
        std::map<std::string, Entrypoint> entryPointNameToEnum;
        std::map<gl_t, std::string> EnumGLToName;
    };

    MapCache* MapCache::s_cache = NULL;

}

const char* GetEntryPointName(Entrypoint entryp) {
    return lists::g_EntrypointNames[entryp];
}

Entrypoint GetEntryPointEnum(const char* name) {
    std::map<std::string, Entrypoint>::iterator ret = lists::MapCache::get()->entryPointNameToEnum.find(name);
    if (ret == lists::MapCache::get()->entryPointNameToEnum.end())
        return NO_ENTRYPOINT;
    return ret->second;
}

std::string GetGLEnumName(gl_t glEnum) {
    std::map<gl_t, std::string>::iterator ret = lists::MapCache::get()->EnumGLToName.find(glEnum);
    if (ret == lists::MapCache::get()->EnumGLToName.end()) {
        std::ostringstream tmp;
        tmp << "0x" << std::hex << glEnum;
        return tmp.str();
    }
    return ret->second;
}

std::string GetShaderStageName(gl_t glEnum) {
    switch (glEnum) {
        case GL_VERTEX_SHADER:
            return "Vertex";
        case GL_TESS_CONTROL_SHADER:
            return "Tesselation Control";
        case GL_TESS_EVALUATION_SHADER:
            return "Tesselation Evaluation";
        case GL_GEOMETRY_SHADER:
            return "Geometry";
        case GL_FRAGMENT_SHADER:
            return "Fragment";
        case GL_COMPUTE_SHADER:
            return "Compute";
        default:
            return GetGLEnumName(glEnum).c_str();
    }
}

std::string GetTextureTargetName(gl_t glEnum) {
    switch (glEnum) {
    case GL_TEXTURE_1D:
        return "1D";
    case GL_TEXTURE_2D:
        return "2D";
    case GL_TEXTURE_3D:
        return "3D";
    case GL_TEXTURE_1D_ARRAY:
        return "1D Array";
    case GL_TEXTURE_2D_ARRAY:
        return "2D Array";
    case GL_TEXTURE_RECTANGLE:
        return "Rectangle";
    case GL_TEXTURE_CUBE_MAP:
        return "Cube Map";
    case GL_TEXTURE_CUBE_MAP_ARRAY:
        return "Cube Map Array";
    case GL_TEXTURE_BUFFER:
        return "Buffer";
    case GL_TEXTURE_2D_MULTISAMPLE:
        return "2D MS";
    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
        return "2D MS Array";
    default:
        return GetGLEnumName(glEnum).c_str();
    }
}

namespace call_sets {
    Entrypoint frameDelims[] = {
         wglSwapBuffers_Call,
         wglSwapLayerBuffers_Call,
         wglSwapMultipleBuffers_Call,
         eglSwapBuffers_Call,
         glXSwapBuffers_Call
    };
    Entrypoint drawCalls[] = {
        glDrawElements_Call,
        glDrawElementsBaseVertex_Call,
        glDrawElementsIndirect_Call,
        glDrawElementsInstanced_Call,
        glDrawElementsInstancedARB_Call,
        glDrawElementsInstancedBaseInstance_Call,
        glDrawElementsInstancedBaseVertex_Call,
        glDrawElementsInstancedBaseVertexBaseInstance_Call,
        glDrawElementsInstancedEXT_Call,
        glMultiDrawElements_Call,
        glMultiDrawElementsBaseVertex_Call,
        glMultiDrawElementsEXT_Call,
        glMultiDrawElementsIndirect_Call,
        glMultiDrawElementsIndirectAMD_Call,
        glMultiModeDrawElementsIBM_Call,
        glDrawArrays_Call,
        glDrawArraysEXT_Call,
        glDrawArraysIndirect_Call,
        glDrawArraysInstanced_Call,
        glDrawArraysInstancedARB_Call,
        glDrawArraysInstancedBaseInstance_Call,
        glDrawArraysInstancedEXT_Call,
        glMultiDrawArrays_Call,
        glMultiDrawArraysEXT_Call,
        glMultiDrawArraysIndirect_Call,
        glMultiDrawArraysIndirectAMD_Call,
        glMultiModeDrawArraysIBM_Call,
        glClear_Call,
        glClearBufferfi_Call,
        glClearBufferfv_Call,
        glClearBufferiv_Call,
        glClearBufferuiv_Call,
        glDrawRangeElementArrayAPPLE_Call,
        glDrawRangeElementArrayATI_Call,
        glDrawRangeElements_Call,
        glDrawRangeElementsBaseVertex_Call,
        glDrawRangeElementsEXT_Call,
        glMultiDrawRangeElementArrayAPPLE_Call,
        glEnd_Call,
    };

    std::set<Entrypoint> drawCallSet(&drawCalls[0], &drawCalls[sizeof(drawCalls)/sizeof(drawCalls[0])]);
    std::set<Entrypoint> frameDelimsSet(&frameDelims[0], &frameDelims[sizeof(frameDelims)/sizeof(frameDelims[0])]);
}

bool IsDrawCall(Entrypoint entryp) {
    return call_sets::drawCallSet.find(entryp) != call_sets::drawCallSet.end();
}

bool IsFrameDelimiter(Entrypoint entryp) {
    return call_sets::frameDelimsSet.find(entryp) != call_sets::frameDelimsSet.end();
}
<|endoftext|>