<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"

#include <algorithm>
#include <cstdint>
#include <functional>
#include <limits>
#include <numeric>
#include <string>
#include <tuple>
#include <type_traits>

#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"  // from @llvm-project
#include "mlir/Dialect/Traits.h"  // from @llvm-project
#include "mlir/IR/Attributes.h"  // from @llvm-project
#include "mlir/IR/Builders.h"  // from @llvm-project
#include "mlir/IR/BuiltinAttributes.h"  // from @llvm-project
#include "mlir/IR/BuiltinOps.h"  // from @llvm-project
#include "mlir/IR/BuiltinTypes.h"  // from @llvm-project
#include "mlir/IR/Diagnostics.h"  // from @llvm-project
#include "mlir/IR/DialectImplementation.h"  // from @llvm-project
#include "mlir/IR/Identifier.h"  // from @llvm-project
#include "mlir/IR/Location.h"  // from @llvm-project
#include "mlir/IR/MLIRContext.h"  // from @llvm-project
#include "mlir/IR/Matchers.h"  // from @llvm-project
#include "mlir/IR/OpDefinition.h"  // from @llvm-project
#include "mlir/IR/OpImplementation.h"  // from @llvm-project
#include "mlir/IR/PatternMatch.h"  // from @llvm-project
#include "mlir/IR/TypeUtilities.h"  // from @llvm-project
#include "mlir/IR/Types.h"  // from @llvm-project
#include "mlir/IR/Value.h"  // from @llvm-project
#include "mlir/Interfaces/DecodeAttributesInterfaces.h"  // from @llvm-project
#include "mlir/Interfaces/FoldInterfaces.h"  // from @llvm-project
#include "mlir/Interfaces/SideEffectInterfaces.h"  // from @llvm-project
#include "mlir/Parser.h"  // from @llvm-project
#include "mlir/Support/LLVM.h"  // from @llvm-project
#include "mlir/Support/LogicalResult.h"  // from @llvm-project
#include "mlir/Transforms/InliningUtils.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_attributes.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_side_effects.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_structs.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_def_builder.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/util/tensor_format.h"

// These are currently aliases and the alias will be removed, verified
// equivalent until then.
// TODO(b/178519687): Remvoe once addressed.
static_assert(std::is_same<tensorflow::int64, std::int64_t>::value,
              "tensorflow::int64 is expected to match std::int64_t");

namespace mlir {
namespace TF {

//===----------------------------------------------------------------------===//
// TF Dialect Interfaces
//===----------------------------------------------------------------------===//

namespace {

struct TFConstantFoldInterface : public DialectFoldInterface {
  TFConstantFoldInterface(Dialect *dialect) : DialectFoldInterface(dialect) {}
  LogicalResult fold(Operation *op, ArrayRef<Attribute> operands,
                     SmallVectorImpl<OpFoldResult> &results) const final {
    return TensorFlowDialect::constantFold(op, operands, results);
  }
};

struct TFDecodeAttributesInterface : public DialectDecodeAttributesInterface {
  TFDecodeAttributesInterface(Dialect *dialect)
      : DialectDecodeAttributesInterface(dialect) {}
  LogicalResult decode(OpaqueElementsAttr input,
                       ElementsAttr &output) const override {
    return TensorFlowDialect::decode(input, output);
  }
};

struct TFInlinerInterface : public DialectInlinerInterface {
  using DialectInlinerInterface::DialectInlinerInterface;

  //===--------------------------------------------------------------------===//
  // Analysis Hooks
  //===--------------------------------------------------------------------===//

  // Returns if it's legal to inline 'callable' into the 'call', where 'call' is
  // a TF operation.
  bool isLegalToInline(Operation *call, Operation *callable,
                       bool wouldBeCloned) const final {
    // Check that the TF call operation is one that is legal to inline. Allow
    // inlining all except:
    // 1. StatefulPartitionedCalls with device set. The inlining doesn't
    // propagate the device attribute by default, so disable until either we
    // could set it in inlining interface or use the lower level inline
    // methods.
    // Note: this could be further restricted in future.
    if (auto pcall = dyn_cast<StatefulPartitionedCallOp>(call)) {
      if (auto device = pcall->getAttrOfType<StringAttr>("device"))
        return device.getValue().empty();
    }
    // 2. TPUPartitionedCalls.
    return !isa<TPUPartitionedCallOp>(call);
  }

  // Returns if its legal to inline 'src' region into the 'dest' region
  // attached to a TF operation.
  bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned,
                       BlockAndValueMapping &valueMapping) const final {
    // Allow inlining in regions attached to region based control flow
    // operations only if the src region is a single block region
    return isa<IfRegionOp, WhileRegionOp>(dest->getParentOp()) &&
           llvm::hasSingleElement(*src);
  }

  // Returns true if its legal to inline a TF operation `op` into the `dest`
  // region.
  bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned,
                       BlockAndValueMapping &) const final {
    // An op is legal to inline if either of the following conditions is true:
    // (a) Its legal to duplicate the Op.
    // (b) The Op is inside a single use function. If that function is inlined,
    //     post inlining, the function will be dead and eliminated from the IR.
    //     So there won't be any code duplication.
    // plus the function caller op can be replaced by inlined ops.
    return !wouldBeCloned || TensorFlowDialect::CanDuplicate(op);
  }

  //===--------------------------------------------------------------------===//
  // Transformation Hooks
  //===--------------------------------------------------------------------===//

  // Attempts to materialize a conversion for a type mismatch between a call
  // from this dialect, and a callable region. This method should generate an
  // operation that takes 'input' as the only operand, and produces a single
  // result of 'resultType'. If a conversion can not be generated, nullptr
  // should be returned.
  Operation *materializeCallConversion(OpBuilder &builder, Value input,
                                       Type result_type,
                                       Location conversion_loc) const final {
    if (!result_type.isa<TensorType>() || !input.getType().isa<TensorType>())
      return nullptr;
    return builder.create<TF::CastOp>(conversion_loc, result_type, input,
                                      /*truncate=*/builder.getBoolAttr(false));
  }
};
}  // end anonymous namespace

//===----------------------------------------------------------------------===//
// TF Dialect
//===----------------------------------------------------------------------===//

// Returns true if the op can be duplicated.
bool TensorFlowDialect::CanDuplicate(Operation *op) {
  // If the op is marked with the cannot duplicate trait, it cannot be
  // duplicated.
  if (op->hasTrait<OpTrait::TF::CannotDuplicate>()) return false;

  // If the op has no memory side effects, it can be duplicated.
  if (MemoryEffectOpInterface::hasNoEffect(op)) return true;

  // If the op is marked stateless using the `is_stateless` attribute, that
  // attribute determines if the op can be duplicated.
  if (auto is_stateless = op->getAttrOfType<BoolAttr>("is_stateless"))
    return is_stateless.getValue();

  // Assume ops can be duplicated if modelled.
  return op->isRegistered();
}

// TF dialect fallback for MemoryEffectOpInterface. The filtering for returning
// the interface is done in the return below and here it is empty as it is only
// returned for known not-stateful and unmodelled ops.
struct TensorFlowRegistryEffectInterfaceFallback
    : public MemoryEffectOpInterface::FallbackModel<
          TensorFlowRegistryEffectInterfaceFallback> {
  static bool classof(Operation *op) { return true; }
  void getEffects(
      Operation *op,
      SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
          &effects) const {}
};

void *TensorFlowDialect::getRegisteredInterfaceForOp(
    mlir::TypeID interface, mlir::OperationName opName) {
  if (interface == TypeID::get<mlir::MemoryEffectOpInterface>()) {
    // Don't use fallback for modelled ops.
    if (opName.getAbstractOperation()) return nullptr;

    // Only use fallback interface for known not-stateful ops.
    const tensorflow::OpRegistrationData *op_reg_data = nullptr;
    tensorflow::Status s = tensorflow::OpRegistry::Global()->LookUp(
        opName.stripDialect().str(), &op_reg_data);
    return (s.ok() && !op_reg_data->op_def.is_stateful())
               ? fallback_effect_op_interface_
               : nullptr;
  }

  return nullptr;
}

// Returns true if the op can have side effects.
bool TensorFlowDialect::CanHaveSideEffects(Operation *op) {
  // If the op has no memory side effects, it has no side effects
  if (MemoryEffectOpInterface::hasNoEffect(op)) return false;

  // If the op is marked stateless using the `is_stateless` attribute, then
  // it has no side effects.
  if (auto is_stateless = op->getAttrOfType<BoolAttr>("is_stateless"))
    return !is_stateless.getValue();

  // Terminators defined in the TF dialect do not have side effects.
  if (op->hasTrait<OpTrait::IsTerminator>()) return false;

  // Otherwise assume that the op can have side effects.
  return true;
}

std::vector<TensorFlowDialect::AdditionalOpFunction>
    *TensorFlowDialect::GetAdditionalOperationHooks() {
  static auto *const additional_operation_hooks =
      new std::vector<TensorFlowDialect::AdditionalOpFunction>();
  return additional_operation_hooks;
}

TensorFlowDialect::ConstantFoldHook TensorFlowDialect::constant_fold_hook_;
TensorFlowDialect::DecodeConstantHook TensorFlowDialect::decode_constant_hook_;

TensorFlowDialect::TensorFlowDialect(MLIRContext *context)
    : Dialect(/*name=*/"tf", context, TypeID::get<TensorFlowDialect>()) {
  addOperations<
#define GET_OP_LIST
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_all_ops.cc.inc"
      >();
  addOperations<
#define GET_OP_LIST
#include "tensorflow/compiler/mlir/tensorflow/ir/tfrt_ops.cc.inc"
      >();
  registerTypes();
  addInterfaces<TFInlinerInterface, TFDecodeAttributesInterface,
                TFConstantFoldInterface>();
  fallback_effect_op_interface_ =
      new TensorFlowRegistryEffectInterfaceFallback();
  registerAttributes();

  // Support unknown operations because not all TensorFlow operations are
  // registered.
  allowUnknownOperations();

  for (const auto &hook : *GetAdditionalOperationHooks()) {
    hook(*this);
  }
}

TensorFlowDialect::~TensorFlowDialect() {
  delete fallback_effect_op_interface_;
}

// Parses a type registered to this dialect.
Type TensorFlowDialect::parseType(DialectAsmParser &parser) const {
  StringRef data;
  if (parser.parseKeyword(&data)) return Type();

#define HANDLE_TF_TYPE(tftype, enumerant, name) \
  if (data == name) return tftype##Type::get(getContext());
// Custom TensorFlow types are handled separately at the end as they do partial
// match.
#define HANDLE_CUSTOM_TF_TYPE(tftype, enumerant, name)
// NOLINTNEXTLINE
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.def"

  llvm::SMLoc loc = parser.getNameLoc();
  if (data.startswith("resource")) {
    Type ret = ParseResourceType(parser);
    if (!ret) parser.emitError(loc, "invalid resource type");
    return ret;
  }
  if (data.startswith("variant")) {
    Type ret = ParseVariantType(parser);
    if (!ret) parser.emitError(loc, "invalid variant type");
    return ret;
  }
  return (parser.emitError(loc, "unknown TensorFlow type: " + data), nullptr);
}

// Prints a type registered to this dialect.
void TensorFlowDialect::printType(Type ty, DialectAsmPrinter &os) const {
  assert(ty.isa<TensorFlowType>());
#define HANDLE_TF_TYPE(tftype, enumerant, name)        \
  if (auto derived_ty = ty.dyn_cast<tftype##Type>()) { \
    os << name;                                        \
    return;                                            \
  }
#define HANDLE_CUSTOM_TF_TYPE(tftype, enumerant, name) \
  if (auto derived_ty = ty.dyn_cast<tftype##Type>()) { \
    Print##tftype##Type(derived_ty, os);               \
    return;                                            \
  }
// NOLINTNEXTLINE
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.def"

  llvm_unreachable("unexpected tensorflow type kind");
}

namespace {
template <typename TypeWithSubtype>
Type ParseTypeWithSubtype(MLIRContext *context, DialectAsmParser &parser) {
  // Default type without inferred subtypes.
  if (failed(parser.parseOptionalLess())) return TypeWithSubtype::get(context);

  // Most types with subtypes have only one subtype.
  SmallVector<TensorType, 1> subtypes;
  do {
    TensorType tensor_ty;
    if (parser.parseType(tensor_ty)) return Type();

    // Each of the subtypes should be a valid TensorFlow type.
    // TODO(jpienaar): Remove duplication.
    if (!IsValidTFTensorType(tensor_ty)) {
      parser.emitError(parser.getNameLoc()) << "invalid subtype: " << tensor_ty;
      return Type();
    }
    subtypes.push_back(tensor_ty);
  } while (succeeded(parser.parseOptionalComma()));

  if (parser.parseGreater()) return Type();

  return TypeWithSubtype::get(subtypes, context);
}

template <typename TypeWithSubtype>
void PrintTypeWithSubtype(StringRef type, TypeWithSubtype ty,
                          DialectAsmPrinter &os) {
  os << type;
  ArrayRef<TensorType> subtypes = ty.getSubtypes();
  if (subtypes.empty()) return;

  os << "<";
  interleaveComma(subtypes, os);
  os << ">";
}
}  // anonymous namespace

Type TensorFlowDialect::ParseResourceType(DialectAsmParser &parser) const {
  return ParseTypeWithSubtype<ResourceType>(getContext(), parser);
}

void TensorFlowDialect::PrintResourceType(ResourceType ty,
                                          DialectAsmPrinter &os) const {
  return PrintTypeWithSubtype("resource", ty, os);
}

Type TensorFlowDialect::ParseVariantType(DialectAsmParser &parser) const {
  return ParseTypeWithSubtype<VariantType>(getContext(), parser);
}

void TensorFlowDialect::PrintVariantType(VariantType ty,
                                         DialectAsmPrinter &os) const {
  return PrintTypeWithSubtype("variant", ty, os);
}

Operation *TensorFlowDialect::materializeConstant(OpBuilder &builder,
                                                  Attribute value, Type type,
                                                  Location loc) {
  return builder.create<ConstOp>(loc, type, value);
}

}  // namespace TF
}  // namespace mlir
<commit_msg>Don't inline StatefulPartionedCallOps with devices assigned<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/mlir/tensorflow/ir/tf_ops.h"

#include <algorithm>
#include <cstdint>
#include <functional>
#include <limits>
#include <numeric>
#include <string>
#include <tuple>
#include <type_traits>

#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
#include "mlir/Dialect/StandardOps/IR/Ops.h"  // from @llvm-project
#include "mlir/Dialect/Traits.h"  // from @llvm-project
#include "mlir/IR/Attributes.h"  // from @llvm-project
#include "mlir/IR/Builders.h"  // from @llvm-project
#include "mlir/IR/BuiltinAttributes.h"  // from @llvm-project
#include "mlir/IR/BuiltinOps.h"  // from @llvm-project
#include "mlir/IR/BuiltinTypes.h"  // from @llvm-project
#include "mlir/IR/Diagnostics.h"  // from @llvm-project
#include "mlir/IR/DialectImplementation.h"  // from @llvm-project
#include "mlir/IR/Identifier.h"  // from @llvm-project
#include "mlir/IR/Location.h"  // from @llvm-project
#include "mlir/IR/MLIRContext.h"  // from @llvm-project
#include "mlir/IR/Matchers.h"  // from @llvm-project
#include "mlir/IR/OpDefinition.h"  // from @llvm-project
#include "mlir/IR/OpImplementation.h"  // from @llvm-project
#include "mlir/IR/PatternMatch.h"  // from @llvm-project
#include "mlir/IR/TypeUtilities.h"  // from @llvm-project
#include "mlir/IR/Types.h"  // from @llvm-project
#include "mlir/IR/Value.h"  // from @llvm-project
#include "mlir/Interfaces/DecodeAttributesInterfaces.h"  // from @llvm-project
#include "mlir/Interfaces/FoldInterfaces.h"  // from @llvm-project
#include "mlir/Interfaces/SideEffectInterfaces.h"  // from @llvm-project
#include "mlir/Parser.h"  // from @llvm-project
#include "mlir/Support/LLVM.h"  // from @llvm-project
#include "mlir/Support/LogicalResult.h"  // from @llvm-project
#include "mlir/Transforms/InliningUtils.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_attributes.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_side_effects.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_structs.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_def_builder.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/util/tensor_format.h"

// These are currently aliases and the alias will be removed, verified
// equivalent until then.
// TODO(b/178519687): Remvoe once addressed.
static_assert(std::is_same<tensorflow::int64, std::int64_t>::value,
              "tensorflow::int64 is expected to match std::int64_t");

namespace mlir {
namespace TF {

//===----------------------------------------------------------------------===//
// TF Dialect Interfaces
//===----------------------------------------------------------------------===//

namespace {

struct TFConstantFoldInterface : public DialectFoldInterface {
  TFConstantFoldInterface(Dialect *dialect) : DialectFoldInterface(dialect) {}
  LogicalResult fold(Operation *op, ArrayRef<Attribute> operands,
                     SmallVectorImpl<OpFoldResult> &results) const final {
    return TensorFlowDialect::constantFold(op, operands, results);
  }
};

struct TFDecodeAttributesInterface : public DialectDecodeAttributesInterface {
  TFDecodeAttributesInterface(Dialect *dialect)
      : DialectDecodeAttributesInterface(dialect) {}
  LogicalResult decode(OpaqueElementsAttr input,
                       ElementsAttr &output) const override {
    return TensorFlowDialect::decode(input, output);
  }
};

struct TFInlinerInterface : public DialectInlinerInterface {
  using DialectInlinerInterface::DialectInlinerInterface;

  //===--------------------------------------------------------------------===//
  // Analysis Hooks
  //===--------------------------------------------------------------------===//

  // Returns if it's legal to inline 'callable' into the 'call', where 'call' is
  // a TF operation.
  bool isLegalToInline(Operation *call, Operation *callable,
                       bool wouldBeCloned) const final {
    // Check that the TF call operation is one that is legal to inline.
    return !isa<TPUPartitionedCallOp>(call);
  }

  // Returns if its legal to inline 'src' region into the 'dest' region
  // attached to a TF operation.
  bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned,
                       BlockAndValueMapping &valueMapping) const final {
    // Allow inlining in regions attached to region based control flow
    // operations only if the src region is a single block region
    return isa<IfRegionOp, WhileRegionOp>(dest->getParentOp()) &&
           llvm::hasSingleElement(*src);
  }

  // Returns true if its legal to inline a TF operation `op` into the `dest`
  // region.
  bool isLegalToInline(Operation *op, Region *dest, bool wouldBeCloned,
                       BlockAndValueMapping &) const final {
    // An op is legal to inline if either of the following conditions is true:
    // (a) Its legal to duplicate the Op.
    // (b) The Op is inside a single use function. If that function is inlined,
    //     post inlining, the function will be dead and eliminated from the IR.
    //     So there won't be any code duplication.
    // plus the function caller op can be replaced by inlined ops.
    return !wouldBeCloned || TensorFlowDialect::CanDuplicate(op);
  }

  //===--------------------------------------------------------------------===//
  // Transformation Hooks
  //===--------------------------------------------------------------------===//

  // Attempts to materialize a conversion for a type mismatch between a call
  // from this dialect, and a callable region. This method should generate an
  // operation that takes 'input' as the only operand, and produces a single
  // result of 'resultType'. If a conversion can not be generated, nullptr
  // should be returned.
  Operation *materializeCallConversion(OpBuilder &builder, Value input,
                                       Type result_type,
                                       Location conversion_loc) const final {
    if (!result_type.isa<TensorType>() || !input.getType().isa<TensorType>())
      return nullptr;
    return builder.create<TF::CastOp>(conversion_loc, result_type, input,
                                      /*truncate=*/builder.getBoolAttr(false));
  }
};
}  // end anonymous namespace

//===----------------------------------------------------------------------===//
// TF Dialect
//===----------------------------------------------------------------------===//

// Returns true if the op can be duplicated.
bool TensorFlowDialect::CanDuplicate(Operation *op) {
  // If the op is marked with the cannot duplicate trait, it cannot be
  // duplicated.
  if (op->hasTrait<OpTrait::TF::CannotDuplicate>()) return false;

  // If the op has no memory side effects, it can be duplicated.
  if (MemoryEffectOpInterface::hasNoEffect(op)) return true;

  // If the op is marked stateless using the `is_stateless` attribute, that
  // attribute determines if the op can be duplicated.
  if (auto is_stateless = op->getAttrOfType<BoolAttr>("is_stateless"))
    return is_stateless.getValue();

  // Assume ops can be duplicated if modelled.
  return op->isRegistered();
}

// TF dialect fallback for MemoryEffectOpInterface. The filtering for returning
// the interface is done in the return below and here it is empty as it is only
// returned for known not-stateful and unmodelled ops.
struct TensorFlowRegistryEffectInterfaceFallback
    : public MemoryEffectOpInterface::FallbackModel<
          TensorFlowRegistryEffectInterfaceFallback> {
  static bool classof(Operation *op) { return true; }
  void getEffects(
      Operation *op,
      SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>>
          &effects) const {}
};

void *TensorFlowDialect::getRegisteredInterfaceForOp(
    mlir::TypeID interface, mlir::OperationName opName) {
  if (interface == TypeID::get<mlir::MemoryEffectOpInterface>()) {
    // Don't use fallback for modelled ops.
    if (opName.getAbstractOperation()) return nullptr;

    // Only use fallback interface for known not-stateful ops.
    const tensorflow::OpRegistrationData *op_reg_data = nullptr;
    tensorflow::Status s = tensorflow::OpRegistry::Global()->LookUp(
        opName.stripDialect().str(), &op_reg_data);
    return (s.ok() && !op_reg_data->op_def.is_stateful())
               ? fallback_effect_op_interface_
               : nullptr;
  }

  return nullptr;
}

// Returns true if the op can have side effects.
bool TensorFlowDialect::CanHaveSideEffects(Operation *op) {
  // If the op has no memory side effects, it has no side effects
  if (MemoryEffectOpInterface::hasNoEffect(op)) return false;

  // If the op is marked stateless using the `is_stateless` attribute, then
  // it has no side effects.
  if (auto is_stateless = op->getAttrOfType<BoolAttr>("is_stateless"))
    return !is_stateless.getValue();

  // Terminators defined in the TF dialect do not have side effects.
  if (op->hasTrait<OpTrait::IsTerminator>()) return false;

  // Otherwise assume that the op can have side effects.
  return true;
}

std::vector<TensorFlowDialect::AdditionalOpFunction>
    *TensorFlowDialect::GetAdditionalOperationHooks() {
  static auto *const additional_operation_hooks =
      new std::vector<TensorFlowDialect::AdditionalOpFunction>();
  return additional_operation_hooks;
}

TensorFlowDialect::ConstantFoldHook TensorFlowDialect::constant_fold_hook_;
TensorFlowDialect::DecodeConstantHook TensorFlowDialect::decode_constant_hook_;

TensorFlowDialect::TensorFlowDialect(MLIRContext *context)
    : Dialect(/*name=*/"tf", context, TypeID::get<TensorFlowDialect>()) {
  addOperations<
#define GET_OP_LIST
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_all_ops.cc.inc"
      >();
  addOperations<
#define GET_OP_LIST
#include "tensorflow/compiler/mlir/tensorflow/ir/tfrt_ops.cc.inc"
      >();
  registerTypes();
  addInterfaces<TFInlinerInterface, TFDecodeAttributesInterface,
                TFConstantFoldInterface>();
  fallback_effect_op_interface_ =
      new TensorFlowRegistryEffectInterfaceFallback();
  registerAttributes();

  // Support unknown operations because not all TensorFlow operations are
  // registered.
  allowUnknownOperations();

  for (const auto &hook : *GetAdditionalOperationHooks()) {
    hook(*this);
  }
}

TensorFlowDialect::~TensorFlowDialect() {
  delete fallback_effect_op_interface_;
}

// Parses a type registered to this dialect.
Type TensorFlowDialect::parseType(DialectAsmParser &parser) const {
  StringRef data;
  if (parser.parseKeyword(&data)) return Type();

#define HANDLE_TF_TYPE(tftype, enumerant, name) \
  if (data == name) return tftype##Type::get(getContext());
// Custom TensorFlow types are handled separately at the end as they do partial
// match.
#define HANDLE_CUSTOM_TF_TYPE(tftype, enumerant, name)
// NOLINTNEXTLINE
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.def"

  llvm::SMLoc loc = parser.getNameLoc();
  if (data.startswith("resource")) {
    Type ret = ParseResourceType(parser);
    if (!ret) parser.emitError(loc, "invalid resource type");
    return ret;
  }
  if (data.startswith("variant")) {
    Type ret = ParseVariantType(parser);
    if (!ret) parser.emitError(loc, "invalid variant type");
    return ret;
  }
  return (parser.emitError(loc, "unknown TensorFlow type: " + data), nullptr);
}

// Prints a type registered to this dialect.
void TensorFlowDialect::printType(Type ty, DialectAsmPrinter &os) const {
  assert(ty.isa<TensorFlowType>());
#define HANDLE_TF_TYPE(tftype, enumerant, name)        \
  if (auto derived_ty = ty.dyn_cast<tftype##Type>()) { \
    os << name;                                        \
    return;                                            \
  }
#define HANDLE_CUSTOM_TF_TYPE(tftype, enumerant, name) \
  if (auto derived_ty = ty.dyn_cast<tftype##Type>()) { \
    Print##tftype##Type(derived_ty, os);               \
    return;                                            \
  }
// NOLINTNEXTLINE
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.def"

  llvm_unreachable("unexpected tensorflow type kind");
}

namespace {
template <typename TypeWithSubtype>
Type ParseTypeWithSubtype(MLIRContext *context, DialectAsmParser &parser) {
  // Default type without inferred subtypes.
  if (failed(parser.parseOptionalLess())) return TypeWithSubtype::get(context);

  // Most types with subtypes have only one subtype.
  SmallVector<TensorType, 1> subtypes;
  do {
    TensorType tensor_ty;
    if (parser.parseType(tensor_ty)) return Type();

    // Each of the subtypes should be a valid TensorFlow type.
    // TODO(jpienaar): Remove duplication.
    if (!IsValidTFTensorType(tensor_ty)) {
      parser.emitError(parser.getNameLoc()) << "invalid subtype: " << tensor_ty;
      return Type();
    }
    subtypes.push_back(tensor_ty);
  } while (succeeded(parser.parseOptionalComma()));

  if (parser.parseGreater()) return Type();

  return TypeWithSubtype::get(subtypes, context);
}

template <typename TypeWithSubtype>
void PrintTypeWithSubtype(StringRef type, TypeWithSubtype ty,
                          DialectAsmPrinter &os) {
  os << type;
  ArrayRef<TensorType> subtypes = ty.getSubtypes();
  if (subtypes.empty()) return;

  os << "<";
  interleaveComma(subtypes, os);
  os << ">";
}
}  // anonymous namespace

Type TensorFlowDialect::ParseResourceType(DialectAsmParser &parser) const {
  return ParseTypeWithSubtype<ResourceType>(getContext(), parser);
}

void TensorFlowDialect::PrintResourceType(ResourceType ty,
                                          DialectAsmPrinter &os) const {
  return PrintTypeWithSubtype("resource", ty, os);
}

Type TensorFlowDialect::ParseVariantType(DialectAsmParser &parser) const {
  return ParseTypeWithSubtype<VariantType>(getContext(), parser);
}

void TensorFlowDialect::PrintVariantType(VariantType ty,
                                         DialectAsmPrinter &os) const {
  return PrintTypeWithSubtype("variant", ty, os);
}

Operation *TensorFlowDialect::materializeConstant(OpBuilder &builder,
                                                  Attribute value, Type type,
                                                  Location loc) {
  return builder.create<ConstOp>(loc, type, value);
}

}  // namespace TF
}  // namespace mlir
<|endoftext|>


<commit_before>// Copyright 2011-2020 Google LLC
//
// 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 "third_party/zynamics/binexport/reader/reader_test_util.h"

#include <fstream>

#include "third_party/zynamics/binexport/types.h"
#include "third_party/zynamics/binexport/util/filesystem.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "third_party/absl/status/status.h"
#include "third_party/absl/strings/str_cat.h"

namespace security::binexport {

static std::string* g_test_srcdir{};

absl::Status GetBinExportProtoForTesting(absl::string_view filename,
                                         BinExport2* proto) {
  std::string testfile = JoinPath(*g_test_srcdir, "testdata", filename);
  std::ifstream stream(testfile.c_str(), std::ios::in | std::ios::binary);
  if (!proto->ParseFromIstream(&stream)) {
    return absl::FailedPreconditionError(
        absl::StrCat("Could not parse test file: ", testfile));
  }
  return absl::OkStatus();
}

}  // namespace security::binexport
<commit_msg>Internal change<commit_after>// Copyright 2011-2020 Google LLC
//
// 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 "third_party/zynamics/binexport/reader/reader_test_util.h"

#include <fstream>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "third_party/absl/status/status.h"
#include "third_party/absl/strings/str_cat.h"
#include "third_party/zynamics/binexport/types.h"
#include "third_party/zynamics/binexport/util/filesystem.h"

namespace security::binexport {

static std::string* g_test_srcdir{};

absl::Status GetBinExportProtoForTesting(absl::string_view filename,
                                         BinExport2* proto) {
  const std::string testfile = JoinPath(*g_test_srcdir, "testdata", filename);

  std::ifstream stream(testfile.c_str(), std::ios::in | std::ios::binary);
  if (!proto->ParseFromIstream(&stream)) {
    return absl::FailedPreconditionError(
        absl::StrCat("Could not parse test file: ", testfile));
  }
  return absl::OkStatus();
}

}  // namespace security::binexport

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  security::binexport::g_test_srcdir =
      new std::string(argc >= 2 ? argv[1] : GetCurrentDirectory());
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/contrib/session_bundle/bundle_shim.h"

#include "tensorflow/cc/saved_model/loader.h"
#include "tensorflow/cc/saved_model/signature_constants.h"
#include "tensorflow/contrib/session_bundle/manifest.pb.h"
#include "tensorflow/contrib/session_bundle/session_bundle.h"
#include "tensorflow/contrib/session_bundle/signature.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/protobuf/meta_graph.pb.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/public/session_options.h"

namespace tensorflow {
namespace serving {
namespace {
///////////////////////////////////////////////////////////////////////////////
// Helper functions to check Signature type.

bool IsClassificationSignature(const Signature& signature) {
  return signature.type_case() == Signature::kClassificationSignature;
}

bool IsRegressionSignature(const Signature& signature) {
  return signature.type_case() == Signature::kRegressionSignature;
}

///////////////////////////////////////////////////////////////////////////////
// Helper functions to build `Classification`, `Regression` and `Predict`
// SignatureDefs.

SignatureDef BuildRegressionSignatureDef(
    const RegressionSignature& regression_signature) {
  SignatureDef signature_def;
  signature_def.set_method_name(kRegressMethodName);
  internal::AddInputToSignatureDef(regression_signature.input().tensor_name(),
                                   kRegressInputs, &signature_def);
  internal::AddOutputToSignatureDef(regression_signature.output().tensor_name(),
                                    kRegressOutputs, &signature_def);
  return signature_def;
}

SignatureDef BuildClassificationSignatureDef(
    const ClassificationSignature& classification_signature) {
  SignatureDef signature_def;
  signature_def.set_method_name(kClassifyMethodName);
  internal::AddInputToSignatureDef(
      classification_signature.input().tensor_name(), kClassifyInputs,
      &signature_def);
  internal::AddOutputToSignatureDef(
      classification_signature.classes().tensor_name(), kClassifyOutputClasses,
      &signature_def);
  internal::AddOutputToSignatureDef(
      classification_signature.scores().tensor_name(), kClassifyOutputScores,
      &signature_def);
  return signature_def;
}

Status MaybeBuildPredictSignatureDef(MetaGraphDef* meta_graph_def) {
  Signature input_signature, output_signature;
  // Ensure that named signatures corresponding to `inputs` and `outputs` keys
  // exist.
  if (!GetNamedSignature(kPredictInputs, *meta_graph_def, &input_signature)
           .ok() ||
      !GetNamedSignature(kPredictOutputs, *meta_graph_def, &output_signature)
           .ok()) {
    return Status(error::Code::INVALID_ARGUMENT,
                  "Named signatures can only be up-converted if entries "
                  "corresponding to both `inputs` and `outputs` exist.");
  }
  // Ensure the `inputs` and `outputs` named signatures are generic signatures.
  if (input_signature.type_case() != Signature::TypeCase::kGenericSignature ||
      output_signature.type_case() != Signature::TypeCase::kGenericSignature) {
    return Status(error::Code::INVALID_ARGUMENT,
                  "Named signatures corresponding to `inputs` and `outputs` "
                  "can only be up-converted if they are GenericSignatures.");
  }
  SignatureDef signature_def;
  signature_def.set_method_name(kPredictMethodName);
  // Add map entries from the `inputs` generic signature to the input map in the
  // signature def.
  for (const auto& map_entry : input_signature.generic_signature().map()) {
    internal::AddInputToSignatureDef(map_entry.second.tensor_name(),
                                     map_entry.first, &signature_def);
  }
  // Add map entries from the `outputs` generic signature to the output map in
  // the signature def.
  for (const auto& map_entry : output_signature.generic_signature().map()) {
    internal::AddOutputToSignatureDef(map_entry.second.tensor_name(),
                                      map_entry.first, &signature_def);
  }
  // Add the constructed signature def to the signature def map of the meta
  // graph def. Use the default key if it isn't already in use.
  const bool already_has_default_signature =
      meta_graph_def->signature_def().find(kDefaultServingSignatureDefKey) !=
      meta_graph_def->signature_def().end();
  const string signature_def_key =
      already_has_default_signature
          ? strings::StrCat(kDefaultServingSignatureDefKey, "_from_named")
          : kDefaultServingSignatureDefKey;
  (*meta_graph_def->mutable_signature_def())[signature_def_key] = signature_def;
  return Status::OK();
}

Status LoadSavedModelFromLegacySessionBundlePath(
    const SessionOptions& session_options, const RunOptions& run_options,
    const StringPiece session_bundle_export_dir,
    SavedModelBundle* saved_model_bundle) {
  if (session_bundle_export_dir.empty()) {
    return Status(error::Code::NOT_FOUND, "Export directory path is empty.");
  }
  if (!IsPossibleExportDirectory(session_bundle_export_dir)) {
    return Status(
        error::Code::NOT_FOUND,
        "Export directory does not contain a valid SessionBundle export.");
  }

  // Build the session-bundle.
  SessionBundle session_bundle;
  TF_RETURN_IF_ERROR(LoadSessionBundleFromPathUsingRunOptions(
      session_options, run_options, session_bundle_export_dir,
      &session_bundle));

  // Convert the session-bundle to a saved-model-bundle.
  return internal::ConvertSessionBundleToSavedModelBundle(session_bundle,
                                                          saved_model_bundle);
}

///////////////////////////////////////////////////////////////////////////////
// Helper functions to convert `Default` and `Named` signatures to
// SignatureDefs.

// Up-conversion of default signatures is supported for classification and
// regression.
Status ConvertDefaultSignatureToSignatureDef(const Signatures& signatures,
                                             MetaGraphDef* meta_graph_def) {
  if (!signatures.has_default_signature()) {
    return Status::OK();
  }
  const bool already_has_default_signature =
      meta_graph_def->signature_def().find(kDefaultServingSignatureDefKey) !=
      meta_graph_def->signature_def().end();
  if (already_has_default_signature) {
    return Status(error::Code::ALREADY_EXISTS,
                  strings::StrCat(
                      "Gefault signature cannot be up-converted since ",
                      kDefaultServingSignatureDefKey, " key already exists."));
  }
  const Signature& signature = signatures.default_signature();
  if (IsRegressionSignature(signature)) {
    (*meta_graph_def->mutable_signature_def())[kDefaultServingSignatureDefKey] =
        BuildRegressionSignatureDef(signature.regression_signature());
  } else if (IsClassificationSignature(signature)) {
    (*meta_graph_def->mutable_signature_def())[kDefaultServingSignatureDefKey] =
        BuildClassificationSignatureDef(signature.classification_signature());
  } else {
    return Status(error::Code::UNIMPLEMENTED,
                  "Default signature up-conversion to SignatureDef is only "
                  "supported for classification and regression.");
  }
  return Status::OK();
}

Status ConvertNamedSignaturesToSignatureDef(const Signatures& signatures,
                                            MetaGraphDef* meta_graph_def) {
  if (signatures.named_signatures().empty()) {
    return Status::OK();
  }
  // Check for a Predict signature for up-conversion.
  Status predict_signature_def_status =
      MaybeBuildPredictSignatureDef(meta_graph_def);
  for (const auto& it_named_signature : signatures.named_signatures()) {
    const string key = it_named_signature.first;
    // If a Predict SignatureDef was successfully constructed, skip the entries
    // corresponding to `inputs` and `outputs`.
    if (predict_signature_def_status.ok()) {
      if (key == kPredictInputs || key == kPredictOutputs) {
        continue;
      }
    }
    SignatureDef signature_def;
    const Signature signature = it_named_signature.second;
    if (IsRegressionSignature(signature)) {
      (*meta_graph_def->mutable_signature_def())[key] =
          BuildRegressionSignatureDef(signature.regression_signature());
    } else if (IsClassificationSignature(signature)) {
      (*meta_graph_def->mutable_signature_def())[key] = signature_def;
      BuildClassificationSignatureDef(signature.classification_signature());
    } else {
      return Status(error::Code::INVALID_ARGUMENT,
                    "Named signature up-conversion is can only be up-converted "
                    "if they are "
                    "`Classification`, `Regression` or have two entries called "
                    "`inputs` and `outputs`, corresponding to the `Prediction` "
                    "API. ");
    }
  }
  return Status::OK();
}

}  // namespace

namespace internal {
///////////////////////////////////////////////////////////////////////////////
// Helper functions to populate SignatureDef fields.

// Adds an entry to the `inputs` map of the supplied SignatureDef.
void AddInputToSignatureDef(const string& tensor_name, const string& map_key,
                            SignatureDef* signature_def) {
  if (tensor_name.empty()) {
    return;
  }
  // TensorInfo messages used in the SignatureDefs are thinly populated with
  // name only.
  TensorInfo tensor_info;
  tensor_info.set_name(tensor_name);
  (*signature_def->mutable_inputs())[map_key] = tensor_info;
}

// Adds an entry to the `outputs` map of the supplied SignatureDef.
void AddOutputToSignatureDef(const string& tensor_name, const string& map_key,
                             SignatureDef* signature_def) {
  if (tensor_name.empty()) {
    return;
  }
  // TensorInfo messages used in the SignatureDefs are thinly populated with
  // name only.
  TensorInfo tensor_info;
  tensor_info.set_name(tensor_name);
  (*signature_def->mutable_outputs())[map_key] = tensor_info;
}

// Converts SessionBundle signatures to SavedModel signature-defs.
Status ConvertSignaturesToSignatureDefs(MetaGraphDef* meta_graph_def) {
  Signatures signatures;
  GetSignatures(*meta_graph_def, &signatures);
  TF_RETURN_IF_ERROR(
      ConvertDefaultSignatureToSignatureDef(signatures, meta_graph_def));
  TF_RETURN_IF_ERROR(
      ConvertNamedSignaturesToSignatureDef(signatures, meta_graph_def));
  return Status::OK();
}

// Converts a SessionBundle to a SavedModelBundle.
Status ConvertSessionBundleToSavedModelBundle(
    SessionBundle& session_bundle, SavedModelBundle* saved_model_bundle) {
  // Transfer ownership of the session from old to new.
  saved_model_bundle->session = std::move(session_bundle.session);

  // Copy the meta graph def from the SessionBundle to the SavedModelBundle.
  saved_model_bundle->meta_graph_def.CopyFrom(session_bundle.meta_graph_def);

  // Convert signatures from session-bundle to signature-defs in
  // saved-model-bundle.
  return internal::ConvertSignaturesToSignatureDefs(
      &saved_model_bundle->meta_graph_def);
}

}  // namespace internal

Status LoadSessionBundleOrSavedModelBundle(
    const SessionOptions& session_options, const RunOptions& run_options,
    const string& export_dir,
    const std::unordered_set<string>& saved_model_tags,
    SavedModelBundle* saved_model_bundle) {
  if (MaybeSavedModelDirectory(export_dir)) {
    return LoadSavedModel(session_options, run_options, export_dir,
                          saved_model_tags, saved_model_bundle);
  } else if (IsPossibleExportDirectory(export_dir)) {
    return LoadSavedModelFromLegacySessionBundlePath(
        session_options, run_options, export_dir, saved_model_bundle);
  }
  return Status(error::Code::NOT_FOUND,
                "Session bundle or SavedModel bundle not found at specified "
                "export location");
}

}  // namespace serving
}  // namespace tensorflow
<commit_msg>Use log warnings instead of errors for up-converting generic signatures. Change: 142082843<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/contrib/session_bundle/bundle_shim.h"

#include "tensorflow/cc/saved_model/loader.h"
#include "tensorflow/cc/saved_model/signature_constants.h"
#include "tensorflow/contrib/session_bundle/manifest.pb.h"
#include "tensorflow/contrib/session_bundle/session_bundle.h"
#include "tensorflow/contrib/session_bundle/signature.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/protobuf/meta_graph.pb.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/public/session_options.h"

namespace tensorflow {
namespace serving {
namespace {
///////////////////////////////////////////////////////////////////////////////
// Helper functions to check Signature type.

bool IsClassificationSignature(const Signature& signature) {
  return signature.type_case() == Signature::kClassificationSignature;
}

bool IsRegressionSignature(const Signature& signature) {
  return signature.type_case() == Signature::kRegressionSignature;
}

///////////////////////////////////////////////////////////////////////////////
// Helper functions to build `Classification`, `Regression` and `Predict`
// SignatureDefs.

SignatureDef BuildRegressionSignatureDef(
    const RegressionSignature& regression_signature) {
  SignatureDef signature_def;
  signature_def.set_method_name(kRegressMethodName);
  internal::AddInputToSignatureDef(regression_signature.input().tensor_name(),
                                   kRegressInputs, &signature_def);
  internal::AddOutputToSignatureDef(regression_signature.output().tensor_name(),
                                    kRegressOutputs, &signature_def);
  return signature_def;
}

SignatureDef BuildClassificationSignatureDef(
    const ClassificationSignature& classification_signature) {
  SignatureDef signature_def;
  signature_def.set_method_name(kClassifyMethodName);
  internal::AddInputToSignatureDef(
      classification_signature.input().tensor_name(), kClassifyInputs,
      &signature_def);
  internal::AddOutputToSignatureDef(
      classification_signature.classes().tensor_name(), kClassifyOutputClasses,
      &signature_def);
  internal::AddOutputToSignatureDef(
      classification_signature.scores().tensor_name(), kClassifyOutputScores,
      &signature_def);
  return signature_def;
}

Status MaybeBuildPredictSignatureDef(MetaGraphDef* meta_graph_def) {
  Signature input_signature, output_signature;
  // Ensure that named signatures corresponding to `inputs` and `outputs` keys
  // exist.
  if (!GetNamedSignature(kPredictInputs, *meta_graph_def, &input_signature)
           .ok() ||
      !GetNamedSignature(kPredictOutputs, *meta_graph_def, &output_signature)
           .ok()) {
    return Status(error::Code::INVALID_ARGUMENT,
                  "Named signatures can only be up-converted if entries "
                  "corresponding to both `inputs` and `outputs` exist.");
  }
  // Ensure the `inputs` and `outputs` named signatures are generic signatures.
  if (input_signature.type_case() != Signature::TypeCase::kGenericSignature ||
      output_signature.type_case() != Signature::TypeCase::kGenericSignature) {
    return Status(error::Code::INVALID_ARGUMENT,
                  "Named signatures corresponding to `inputs` and `outputs` "
                  "can only be up-converted if they are GenericSignatures.");
  }
  SignatureDef signature_def;
  signature_def.set_method_name(kPredictMethodName);
  // Add map entries from the `inputs` generic signature to the input map in the
  // signature def.
  for (const auto& map_entry : input_signature.generic_signature().map()) {
    internal::AddInputToSignatureDef(map_entry.second.tensor_name(),
                                     map_entry.first, &signature_def);
  }
  // Add map entries from the `outputs` generic signature to the output map in
  // the signature def.
  for (const auto& map_entry : output_signature.generic_signature().map()) {
    internal::AddOutputToSignatureDef(map_entry.second.tensor_name(),
                                      map_entry.first, &signature_def);
  }
  // Add the constructed signature def to the signature def map of the meta
  // graph def. Use the default key if it isn't already in use.
  const bool already_has_default_signature =
      meta_graph_def->signature_def().find(kDefaultServingSignatureDefKey) !=
      meta_graph_def->signature_def().end();
  const string signature_def_key =
      already_has_default_signature
          ? strings::StrCat(kDefaultServingSignatureDefKey, "_from_named")
          : kDefaultServingSignatureDefKey;
  (*meta_graph_def->mutable_signature_def())[signature_def_key] = signature_def;
  return Status::OK();
}

Status LoadSavedModelFromLegacySessionBundlePath(
    const SessionOptions& session_options, const RunOptions& run_options,
    const StringPiece session_bundle_export_dir,
    SavedModelBundle* saved_model_bundle) {
  if (session_bundle_export_dir.empty()) {
    return Status(error::Code::NOT_FOUND, "Export directory path is empty.");
  }
  if (!IsPossibleExportDirectory(session_bundle_export_dir)) {
    return Status(
        error::Code::NOT_FOUND,
        "Export directory does not contain a valid SessionBundle export.");
  }

  // Build the session-bundle.
  SessionBundle session_bundle;
  TF_RETURN_IF_ERROR(LoadSessionBundleFromPathUsingRunOptions(
      session_options, run_options, session_bundle_export_dir,
      &session_bundle));

  // Convert the session-bundle to a saved-model-bundle.
  return internal::ConvertSessionBundleToSavedModelBundle(session_bundle,
                                                          saved_model_bundle);
}

///////////////////////////////////////////////////////////////////////////////
// Helper functions to convert `Default` and `Named` signatures to
// SignatureDefs.

// Up-conversion of default signatures is supported for classification and
// regression.
Status ConvertDefaultSignatureToSignatureDef(const Signatures& signatures,
                                             MetaGraphDef* meta_graph_def) {
  if (!signatures.has_default_signature()) {
    return Status::OK();
  }
  const bool already_has_default_signature =
      meta_graph_def->signature_def().find(kDefaultServingSignatureDefKey) !=
      meta_graph_def->signature_def().end();
  if (already_has_default_signature) {
    return Status(error::Code::ALREADY_EXISTS,
                  strings::StrCat(
                      "Default signature cannot be up-converted since ",
                      kDefaultServingSignatureDefKey, " key already exists."));
  }
  const Signature& signature = signatures.default_signature();
  if (IsRegressionSignature(signature)) {
    (*meta_graph_def->mutable_signature_def())[kDefaultServingSignatureDefKey] =
        BuildRegressionSignatureDef(signature.regression_signature());
  } else if (IsClassificationSignature(signature)) {
    (*meta_graph_def->mutable_signature_def())[kDefaultServingSignatureDefKey] =
        BuildClassificationSignatureDef(signature.classification_signature());
  } else {
    LOG(WARNING) << "Default signature up-conversion to SignatureDef is only "
                    "supported for `Classification` and `Regression`. Could "
                    "not up-convert signature: "
                 << signature.DebugString();
  }
  return Status::OK();
}

Status ConvertNamedSignaturesToSignatureDef(const Signatures& signatures,
                                            MetaGraphDef* meta_graph_def) {
  if (signatures.named_signatures().empty()) {
    return Status::OK();
  }
  // Check for a Predict signature for up-conversion.
  Status predict_signature_def_status =
      MaybeBuildPredictSignatureDef(meta_graph_def);
  for (const auto& it_named_signature : signatures.named_signatures()) {
    const string key = it_named_signature.first;
    // If a Predict SignatureDef was successfully constructed, skip the entries
    // corresponding to `inputs` and `outputs`.
    if (predict_signature_def_status.ok()) {
      if (key == kPredictInputs || key == kPredictOutputs) {
        continue;
      }
    }
    SignatureDef signature_def;
    const Signature signature = it_named_signature.second;
    if (IsRegressionSignature(signature)) {
      (*meta_graph_def->mutable_signature_def())[key] =
          BuildRegressionSignatureDef(signature.regression_signature());
    } else if (IsClassificationSignature(signature)) {
      (*meta_graph_def->mutable_signature_def())[key] = signature_def;
      BuildClassificationSignatureDef(signature.classification_signature());
    } else {
      LOG(WARNING)
          << "Named signature up-conversion to SignatureDef is only supported "
             "for `Classification`, `Regression` or if two `GenericSignatures` "
             "signatures  called `inputs` and `outputs` exist, corresponding "
             "to the `Prediction` API. Could not up-convert signature: "
          << signature.DebugString();
    }
  }
  return Status::OK();
}

}  // namespace

namespace internal {
///////////////////////////////////////////////////////////////////////////////
// Helper functions to populate SignatureDef fields.

// Adds an entry to the `inputs` map of the supplied SignatureDef.
void AddInputToSignatureDef(const string& tensor_name, const string& map_key,
                            SignatureDef* signature_def) {
  if (tensor_name.empty()) {
    return;
  }
  // TensorInfo messages used in the SignatureDefs are thinly populated with
  // name only.
  TensorInfo tensor_info;
  tensor_info.set_name(tensor_name);
  (*signature_def->mutable_inputs())[map_key] = tensor_info;
}

// Adds an entry to the `outputs` map of the supplied SignatureDef.
void AddOutputToSignatureDef(const string& tensor_name, const string& map_key,
                             SignatureDef* signature_def) {
  if (tensor_name.empty()) {
    return;
  }
  // TensorInfo messages used in the SignatureDefs are thinly populated with
  // name only.
  TensorInfo tensor_info;
  tensor_info.set_name(tensor_name);
  (*signature_def->mutable_outputs())[map_key] = tensor_info;
}

// Converts SessionBundle signatures to SavedModel signature-defs.
Status ConvertSignaturesToSignatureDefs(MetaGraphDef* meta_graph_def) {
  Signatures signatures;
  GetSignatures(*meta_graph_def, &signatures);
  TF_RETURN_IF_ERROR(
      ConvertDefaultSignatureToSignatureDef(signatures, meta_graph_def));
  TF_RETURN_IF_ERROR(
      ConvertNamedSignaturesToSignatureDef(signatures, meta_graph_def));
  return Status::OK();
}

// Converts a SessionBundle to a SavedModelBundle.
Status ConvertSessionBundleToSavedModelBundle(
    SessionBundle& session_bundle, SavedModelBundle* saved_model_bundle) {
  // Transfer ownership of the session from old to new.
  saved_model_bundle->session = std::move(session_bundle.session);

  // Copy the meta graph def from the SessionBundle to the SavedModelBundle.
  saved_model_bundle->meta_graph_def.CopyFrom(session_bundle.meta_graph_def);

  // Convert signatures from session-bundle to signature-defs in
  // saved-model-bundle.
  return internal::ConvertSignaturesToSignatureDefs(
      &saved_model_bundle->meta_graph_def);
}

}  // namespace internal

Status LoadSessionBundleOrSavedModelBundle(
    const SessionOptions& session_options, const RunOptions& run_options,
    const string& export_dir,
    const std::unordered_set<string>& saved_model_tags,
    SavedModelBundle* saved_model_bundle) {
  if (MaybeSavedModelDirectory(export_dir)) {
    return LoadSavedModel(session_options, run_options, export_dir,
                          saved_model_tags, saved_model_bundle);
  } else if (IsPossibleExportDirectory(export_dir)) {
    return LoadSavedModelFromLegacySessionBundlePath(
        session_options, run_options, export_dir, saved_model_bundle);
  }
  return Status(error::Code::NOT_FOUND,
                "Session bundle or SavedModel bundle not found at specified "
                "export location");
}

}  // namespace serving
}  // namespace tensorflow
<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// 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.

/// Render Tests for the OsgOctreeRepresentation class.

#include "SurgSim/DataStructures/EmptyData.h"
#include "SurgSim/DataStructures/OctreeNode.h"
#include "SurgSim/Graphics/RenderTests/RenderTest.h"
#include "SurgSim/Graphics/OctreeRepresentation.h"
#include "SurgSim/Graphics/OsgOctreeRepresentation.h"
#include "SurgSim/Math/OctreeShape.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Math/RigidTransform.h"

using SurgSim::Graphics::OsgOctreeRepresentation;
using SurgSim::Graphics::OctreeRepresentation;
using SurgSim::Math::OctreeShape;
using SurgSim::Math::Vector3d;
using SurgSim::Math::makeRigidTransform;
using SurgSim::Math::makeRotationQuaternion;

struct OsgOctreeRepresentationRenderTests : public SurgSim::Graphics::RenderTest
{
};

// An Octree(Node) is traversed in following order (the 2nd OctreeNode, i.e. OctreeNode with "1" is now shown):
/*
				________
			   /3  /  7/|
			  /-------/ |
			 /2__/_6_/| |
			|   |   | |/|
			|___|___|/|5|
			|   |   | |/
			|0__|__4|/
*/
TEST_F(OsgOctreeRepresentationRenderTests, OctreeSubdivide)
{
	SurgSim::DataStructures::EmptyData emptyData;

	SurgSim::Math::OctreeShape::NodeType::AxisAlignedBoundingBox boundingBox;
	boundingBox.min() = Vector3d::Ones() * -0.2;
	boundingBox.max() = Vector3d::Ones() * 0.2;

	std::array<Vector3d, 8> secondLevelPositions = {{ Vector3d(-0.1, -0.1, -0.1),
													  Vector3d( 0.1, -0.1, -0.1),
													  Vector3d(-0.1,  0.1, -0.1),
													  Vector3d( 0.1,  0.1, -0.1),
													  Vector3d(-0.1, -0.1,  0.1),
													  Vector3d( 0.1, -0.1,  0.1),
													  Vector3d(-0.1,  0.1,  0.1),
													  Vector3d( 0.1,  0.1,  0.1)
												   }};
	auto octree = std::make_shared<OctreeShape::NodeType>(boundingBox);
	octree->addData(secondLevelPositions[0], emptyData, 2);
	octree->addData(secondLevelPositions[1], emptyData, 2);
	octree->addData(secondLevelPositions[3], emptyData, 2);
	octree->addData(secondLevelPositions[7], emptyData, 2);
	octree->addData(Vector3d(0.2, 0.2, 0.01), emptyData, 3);
	octree->addData(Vector3d(-0.2, -0.2, 0.2), emptyData, 3);
	octree->addData(Vector3d(0.01, 0.01, 0.11), emptyData, 3);
	octree->addData(Vector3d(0.01, 0.01, 0.11), emptyData, 4);

	OctreeShape octreeShape;
	octreeShape.setRootNode(octree);

	auto octreeRepresentation = std::make_shared<OsgOctreeRepresentation>("Octree Representation");
	octreeRepresentation->setLocalPose(makeRigidTransform(
											makeRotationQuaternion(M_PI_4, Vector3d(1.0, 1.0, 1.0)),
											Vector3d(0.0, 0.0, -1.0))
										);
	viewElement->addComponent(octreeRepresentation);
	octreeRepresentation->setOctree(octreeShape);

	// Path to a leaf node
	SurgSim::DataStructures::OctreePath path0;
	path0.push_back(2);

	// Path to a leaf node
	SurgSim::DataStructures::OctreePath path1;
	path1.push_back(7);
	path1.push_back(3);

	// Path to a internal OctreeNode
	SurgSim::DataStructures::OctreePath path2;
	path2.push_back(4);

	SurgSim::DataStructures::OctreePath invalidPath;
	invalidPath.push_back(0);
	invalidPath.push_back(1);

	/// Run the thread
	runtime->start();
	EXPECT_TRUE(graphicsManager->isInitialized());
	EXPECT_TRUE(viewElement->isInitialized());
	boost::this_thread::sleep(boost::posix_time::milliseconds(2000));

	octreeRepresentation->setNodeVisible(path0, true);
	boost::this_thread::sleep(boost::posix_time::milliseconds(2000));

	octreeRepresentation->setNodeVisible(path1, false);
	boost::this_thread::sleep(boost::posix_time::milliseconds(2000));

	octreeRepresentation->setNodeVisible(path2, false);
	boost::this_thread::sleep(boost::posix_time::milliseconds(2000));

	EXPECT_ANY_THROW(octreeRepresentation->setNodeVisible(invalidPath, true));
}
<commit_msg>Shorten time on OctreeRenderTest<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// 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.

/// Render Tests for the OsgOctreeRepresentation class.

#include "SurgSim/DataStructures/EmptyData.h"
#include "SurgSim/DataStructures/OctreeNode.h"
#include "SurgSim/Graphics/RenderTests/RenderTest.h"
#include "SurgSim/Graphics/OctreeRepresentation.h"
#include "SurgSim/Graphics/OsgOctreeRepresentation.h"
#include "SurgSim/Math/OctreeShape.h"
#include "SurgSim/Math/Quaternion.h"
#include "SurgSim/Math/Vector.h"
#include "SurgSim/Math/RigidTransform.h"

using SurgSim::Graphics::OsgOctreeRepresentation;
using SurgSim::Graphics::OctreeRepresentation;
using SurgSim::Math::OctreeShape;
using SurgSim::Math::Vector3d;
using SurgSim::Math::makeRigidTransform;
using SurgSim::Math::makeRotationQuaternion;

struct OsgOctreeRepresentationRenderTests : public SurgSim::Graphics::RenderTest
{
};

// An Octree(Node) is traversed in following order (the 2nd OctreeNode, i.e. OctreeNode with "1" is now shown):
/*
				________
			   /3  /  7/|
			  /-------/ |
			 /2__/_6_/| |
			|   |   | |/|
			|___|___|/|5|
			|   |   | |/
			|0__|__4|/
*/
TEST_F(OsgOctreeRepresentationRenderTests, OctreeSubdivide)
{
	SurgSim::DataStructures::EmptyData emptyData;

	SurgSim::Math::OctreeShape::NodeType::AxisAlignedBoundingBox boundingBox;
	boundingBox.min() = Vector3d::Ones() * -0.2;
	boundingBox.max() = Vector3d::Ones() * 0.2;

	std::array<Vector3d, 8> secondLevelPositions = {{
			Vector3d(-0.1, -0.1, -0.1),
			Vector3d(0.1, -0.1, -0.1),
			Vector3d(-0.1,  0.1, -0.1),
			Vector3d(0.1,  0.1, -0.1),
			Vector3d(-0.1, -0.1,  0.1),
			Vector3d(0.1, -0.1,  0.1),
			Vector3d(-0.1,  0.1,  0.1),
			Vector3d(0.1,  0.1,  0.1)
		}
	};
	auto octree = std::make_shared<OctreeShape::NodeType>(boundingBox);
	octree->addData(secondLevelPositions[0], emptyData, 2);
	octree->addData(secondLevelPositions[1], emptyData, 2);
	octree->addData(secondLevelPositions[3], emptyData, 2);
	octree->addData(secondLevelPositions[7], emptyData, 2);
	octree->addData(Vector3d(0.2, 0.2, 0.01), emptyData, 3);
	octree->addData(Vector3d(-0.2, -0.2, 0.2), emptyData, 3);
	octree->addData(Vector3d(0.01, 0.01, 0.11), emptyData, 3);
	octree->addData(Vector3d(0.01, 0.01, 0.11), emptyData, 4);

	OctreeShape octreeShape;
	octreeShape.setRootNode(octree);

	auto octreeRepresentation = std::make_shared<OsgOctreeRepresentation>("Octree Representation");
	octreeRepresentation->setLocalPose(makeRigidTransform(
										   makeRotationQuaternion(M_PI_4, Vector3d(1.0, 1.0, 1.0)),
										   Vector3d(0.0, 0.0, -1.0))
									  );
	viewElement->addComponent(octreeRepresentation);
	octreeRepresentation->setOctree(octreeShape);

	// Path to a leaf node
	SurgSim::DataStructures::OctreePath path0;
	path0.push_back(2);

	// Path to a leaf node
	SurgSim::DataStructures::OctreePath path1;
	path1.push_back(7);
	path1.push_back(3);

	// Path to a internal OctreeNode
	SurgSim::DataStructures::OctreePath path2;
	path2.push_back(4);

	SurgSim::DataStructures::OctreePath invalidPath;
	invalidPath.push_back(0);
	invalidPath.push_back(1);

	/// Run the thread
	runtime->start();
	EXPECT_TRUE(graphicsManager->isInitialized());
	EXPECT_TRUE(viewElement->isInitialized());
	boost::this_thread::sleep(boost::posix_time::milliseconds(1000));

	octreeRepresentation->setNodeVisible(path0, true);
	boost::this_thread::sleep(boost::posix_time::milliseconds(500));

	octreeRepresentation->setNodeVisible(path1, false);
	boost::this_thread::sleep(boost::posix_time::milliseconds(500));

	octreeRepresentation->setNodeVisible(path2, false);
	boost::this_thread::sleep(boost::posix_time::milliseconds(500));

	EXPECT_ANY_THROW(octreeRepresentation->setNodeVisible(invalidPath, true));
}
<|endoftext|>


<commit_before>#include <fstream>
#include <sstream>

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/alert_types.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::create_directory;
using namespace libtorrent;

void print_alerts(libtorrent::session& ses, char const* name, bool allow_disconnects, bool allow_no_torrents)
{
	std::vector<torrent_handle> handles = ses.get_torrents();
	TEST_CHECK(!handles.empty() || allow_no_torrents);
	torrent_handle h;
	if (!handles.empty()) h = handles[0];
	std::auto_ptr<alert> a;
	a = ses.pop_alert();
	while (a.get())
	{
		std::cerr << name << ": " << a->msg() << "\n";
		TEST_CHECK(dynamic_cast<peer_error_alert*>(a.get()) == 0
			|| (!handles.empty() && h.is_seed())
			|| a->msg() == "connecting to peer"
			|| a->msg() == "closing connection to ourself"
			|| a->msg() == "duplicate connection"
			|| (allow_disconnects && a->msg() == "End of file."));
		a = ses.pop_alert();
	}
}

void test_sleep(int millisec)
{
	boost::xtime xt;
	boost::xtime_get(&xt, boost::TIME_UTC);
	boost::uint64_t nanosec = (millisec % 1000) * 1000000 + xt.nsec;
	int sec = millisec / 1000;
	if (nanosec > 1000000000)
	{
		nanosec -= 1000000000;
		sec++;
	}
	xt.nsec = nanosec;
	xt.sec += sec;
	boost::thread::sleep(xt);
}

void stop_web_server(int port)
{
	std::stringstream cmd;
	cmd << "kill `cat ./lighty" << port << ".pid` >/dev/null";
	system(cmd.str().c_str());
}

void start_web_server(int port)
{
	stop_web_server(port);
	std::ofstream f("./lighty_config");
	f << "server.modules = (\"mod_access\")\n"
		"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
		"server.range-requests = \"enable\"\n"
		"server.port = " << port << "\n"
		"server.pid-file = \"./lighty" << port << ".pid\"\n";
	f.close();

	system("lighttpd -f lighty_config &");
	test_sleep(1000);
}

void stop_proxy(int port)
{
	std::stringstream cmd;
	cmd << "delegated -P" << port << " -Fkill";
	system(cmd.str().c_str());
}

void start_proxy(int port, int proxy_type)
{
	using namespace libtorrent;

	stop_proxy(port);
	std::stringstream cmd;
	// we need to echo n since dg will ask us to configure it
	cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com";
	switch (proxy_type)
	{
		case proxy_settings::socks4:
			cmd << " SERVER=socks4";
			break;
		case proxy_settings::socks5:
			cmd << " SERVER=socks5";
			break;
		case proxy_settings::socks5_pw:
			cmd << " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
			break;
		case proxy_settings::http:
			cmd << " SERVER=http";
			break;
		case proxy_settings::http_pw:
			cmd << " SERVER=http AUTHORIZER=-list{testuser:testpass}";
			break;
	}
	system(cmd.str().c_str());
}

using namespace libtorrent;

template <class T>
boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
{
	return boost::intrusive_ptr<T>(new T(*ptr));
}

boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file)
{
	char const* tracker_url = "http://non-existent-name.com/announce";

	using namespace boost::filesystem;

	boost::intrusive_ptr<torrent_info> t(new torrent_info);
	int total_size = 2 * 1024 * 1024;
	t->add_file(path("temporary"), total_size);
	t->set_piece_size(16 * 1024);
	t->add_tracker(tracker_url);

	std::vector<char> piece(16 * 1024);
	for (int i = 0; i < int(piece.size()); ++i)
		piece[i] = (i % 26) + 'A';

	// calculate the hash for all pieces
	int num = t->num_pieces();
	sha1_hash ph = hasher(&piece[0], piece.size()).final();
	for (int i = 0; i < num; ++i)
		t->set_hash(i, ph);
	t->create_torrent();

	if (file)
	{
		while (total_size > 0)
		{
			file->write(&piece[0], (std::min)(int(piece.size()), total_size));
			total_size -= piece.size();
		}
	}

	return t;
}

boost::tuple<torrent_handle, torrent_handle, torrent_handle>
setup_transfer(session* ses1, session* ses2, session* ses3
	, bool clear_files, bool use_metadata_transfer, bool connect_peers
	, std::string suffix)
{
	using namespace boost::filesystem;

	assert(ses1);
	assert(ses2);

	assert(ses1->id() != ses2->id());
	if (ses3)
		assert(ses3->id() != ses2->id());

	create_directory("./tmp1" + suffix);
	std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = create_torrent(&file);
	file.close();
	if (clear_files)
	{
		remove_all("./tmp2" + suffix + "/temporary");
		remove_all("./tmp3" + suffix + "/temporary");
	}

	std::cerr << "generated torrent: " << t->info_hash() << std::endl;

	ses1->set_severity_level(alert::debug);
	ses2->set_severity_level(alert::debug);

	// they should not use the same save dir, because the
	// file pool will complain if two torrents are trying to
	// use the same files
	sha1_hash info_hash = t->info_hash();
	torrent_handle tor1 = ses1->add_torrent(clone_ptr(t), "./tmp1" + suffix);
	TEST_CHECK(!ses1->get_torrents().empty());
	torrent_handle tor2;
	torrent_handle tor3;
	if (ses3)
	{
		tor3 = ses3->add_torrent(clone_ptr(t), "./tmp3" + suffix);
		TEST_CHECK(!ses3->get_torrents().empty());
	}

  	if (use_metadata_transfer)
		tor2 = ses2->add_torrent("http://non-existent-name.com/announce"
		, t->info_hash(), 0, "./tmp2" + suffix);
	else
		tor2 = ses2->add_torrent(clone_ptr(t), "./tmp2" + suffix);
	TEST_CHECK(!ses2->get_torrents().empty());

	assert(ses1->get_torrents().size() == 1);
	assert(ses2->get_torrents().size() == 1);

	test_sleep(100);

	if (connect_peers)
	{
		std::cerr << "connecting peer\n";
		tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
			, ses2->listen_port()));

		if (ses3)
		{
			// give the other peers some time to get an initial
			// set of pieces before they start sharing with each-other
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses2->listen_port()));
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses1->listen_port()));
		}
	}

	return boost::make_tuple(tor1, tor2, tor3);
}

<commit_msg>updated tests<commit_after>#include <fstream>
#include <sstream>

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>

#include "test.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/alert_types.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::create_directory;
using namespace libtorrent;

void print_alerts(libtorrent::session& ses, char const* name, bool allow_disconnects, bool allow_no_torrents)
{
	std::vector<torrent_handle> handles = ses.get_torrents();
	TEST_CHECK(!handles.empty() || allow_no_torrents);
	torrent_handle h;
	if (!handles.empty()) h = handles[0];
	std::auto_ptr<alert> a;
	a = ses.pop_alert();
	while (a.get())
	{
		if (a->msg() != "block downloading"
			&& a->msg() != "block finished"
			&& a->msg() != "piece finished")
			std::cerr << name << ": " << a->msg() << "\n";
		TEST_CHECK(dynamic_cast<peer_error_alert*>(a.get()) == 0
			|| (!handles.empty() && h.is_seed())
			|| a->msg() == "connecting to peer"
			|| a->msg() == "closing connection to ourself"
			|| a->msg() == "duplicate connection"
			|| (allow_disconnects && a->msg() == "End of file."));
		a = ses.pop_alert();
	}
}

void test_sleep(int millisec)
{
	boost::xtime xt;
	boost::xtime_get(&xt, boost::TIME_UTC);
	boost::uint64_t nanosec = (millisec % 1000) * 1000000 + xt.nsec;
	int sec = millisec / 1000;
	if (nanosec > 1000000000)
	{
		nanosec -= 1000000000;
		sec++;
	}
	xt.nsec = nanosec;
	xt.sec += sec;
	boost::thread::sleep(xt);
}

void stop_web_server(int port)
{
	std::stringstream cmd;
	cmd << "kill `cat ./lighty" << port << ".pid` >/dev/null";
	system(cmd.str().c_str());
}

void start_web_server(int port)
{
	stop_web_server(port);
	std::ofstream f("./lighty_config");
	f << "server.modules = (\"mod_access\")\n"
		"server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
		"server.range-requests = \"enable\"\n"
		"server.port = " << port << "\n"
		"server.pid-file = \"./lighty" << port << ".pid\"\n";
	f.close();

	system("lighttpd -f lighty_config &");
	test_sleep(1000);
}

void stop_proxy(int port)
{
	std::stringstream cmd;
	cmd << "delegated -P" << port << " -Fkill";
	system(cmd.str().c_str());
}

void start_proxy(int port, int proxy_type)
{
	using namespace libtorrent;

	stop_proxy(port);
	std::stringstream cmd;
	// we need to echo n since dg will ask us to configure it
	cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com";
	switch (proxy_type)
	{
		case proxy_settings::socks4:
			cmd << " SERVER=socks4";
			break;
		case proxy_settings::socks5:
			cmd << " SERVER=socks5";
			break;
		case proxy_settings::socks5_pw:
			cmd << " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
			break;
		case proxy_settings::http:
			cmd << " SERVER=http";
			break;
		case proxy_settings::http_pw:
			cmd << " SERVER=http AUTHORIZER=-list{testuser:testpass}";
			break;
	}
	system(cmd.str().c_str());
}

using namespace libtorrent;

template <class T>
boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
{
	return boost::intrusive_ptr<T>(new T(*ptr));
}

boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file)
{
	char const* tracker_url = "http://non-existent-name.com/announce";

	using namespace boost::filesystem;

	boost::intrusive_ptr<torrent_info> t(new torrent_info);
	int total_size = 2 * 1024 * 1024;
	t->add_file(path("temporary"), total_size);
	t->set_piece_size(16 * 1024);
	t->add_tracker(tracker_url);

	std::vector<char> piece(16 * 1024);
	for (int i = 0; i < int(piece.size()); ++i)
		piece[i] = (i % 26) + 'A';

	// calculate the hash for all pieces
	int num = t->num_pieces();
	sha1_hash ph = hasher(&piece[0], piece.size()).final();
	for (int i = 0; i < num; ++i)
		t->set_hash(i, ph);
	t->create_torrent();

	if (file)
	{
		while (total_size > 0)
		{
			file->write(&piece[0], (std::min)(int(piece.size()), total_size));
			total_size -= piece.size();
		}
	}

	return t;
}

boost::tuple<torrent_handle, torrent_handle, torrent_handle>
setup_transfer(session* ses1, session* ses2, session* ses3
	, bool clear_files, bool use_metadata_transfer, bool connect_peers
	, std::string suffix)
{
	using namespace boost::filesystem;

	assert(ses1);
	assert(ses2);

	assert(ses1->id() != ses2->id());
	if (ses3)
		assert(ses3->id() != ses2->id());

	create_directory("./tmp1" + suffix);
	std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = create_torrent(&file);
	file.close();
	if (clear_files)
	{
		remove_all("./tmp2" + suffix + "/temporary");
		remove_all("./tmp3" + suffix + "/temporary");
	}

	std::cerr << "generated torrent: " << t->info_hash() << std::endl;

	ses1->set_severity_level(alert::debug);
	ses2->set_severity_level(alert::debug);

	// they should not use the same save dir, because the
	// file pool will complain if two torrents are trying to
	// use the same files
	sha1_hash info_hash = t->info_hash();
	torrent_handle tor1 = ses1->add_torrent(clone_ptr(t), "./tmp1" + suffix);
	TEST_CHECK(!ses1->get_torrents().empty());
	torrent_handle tor2;
	torrent_handle tor3;
	if (ses3)
	{
		tor3 = ses3->add_torrent(clone_ptr(t), "./tmp3" + suffix);
		TEST_CHECK(!ses3->get_torrents().empty());
	}

  	if (use_metadata_transfer)
		tor2 = ses2->add_torrent("http://non-existent-name.com/announce"
		, t->info_hash(), 0, "./tmp2" + suffix);
	else
		tor2 = ses2->add_torrent(clone_ptr(t), "./tmp2" + suffix);
	TEST_CHECK(!ses2->get_torrents().empty());

	assert(ses1->get_torrents().size() == 1);
	assert(ses2->get_torrents().size() == 1);

	test_sleep(100);

	if (connect_peers)
	{
		std::cerr << "connecting peer\n";
		tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
			, ses2->listen_port()));

		if (ses3)
		{
			// give the other peers some time to get an initial
			// set of pieces before they start sharing with each-other
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses2->listen_port()));
			tor3.connect_peer(tcp::endpoint(
				address::from_string("127.0.0.1")
				, ses1->listen_port()));
		}
	}

	return boost::make_tuple(tor1, tor2, tor3);
}

<|endoftext|>


<commit_before>// Copyright (c) 2012 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 <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#define SHADER(Src) #Src

namespace gpu {

class DepthTextureTest : public testing::Test {
 protected:
  static const GLsizei kResolution = 64;
  virtual void SetUp() {
    GLManager::Options options;
    options.size = gfx::Size(kResolution, kResolution);
    gl_.Initialize(options);
  }

  virtual void TearDown() {
    gl_.Destroy();
  }

  GLuint SetupUnitQuad(GLint position_location);

  GLManager gl_;
};

GLuint DepthTextureTest::SetupUnitQuad(GLint position_location) {
  GLuint vbo = 0;
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  static float vertices[] = {
      1.0f,  1.0f,  1.0f,
     -1.0f,  1.0f,  0.0f,
     -1.0f, -1.0f, -1.0f,
      1.0f,  1.0f,  1.0f,
     -1.0f, -1.0f, -1.0f,
      1.0f, -1.0f,  0.0f,
  };
  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  glEnableVertexAttribArray(position_location);
  glVertexAttribPointer(position_location, 3, GL_FLOAT, GL_FALSE, 0, 0);

  return vbo;
}

namespace {

struct FormatType {
  GLenum format;
  GLenum type;
};

}  // anonymous namespace

// crbug.com/135229
// Fails on Win Intel, Linux Intel.
#if ((defined(OS_WIN) || defined(OS_LINUX)) && defined(NDEBUG))
#define MAYBE_RenderTo DISABLED_RenderTo
#else
#define MAYBE_RenderTo RenderTo
#endif

TEST_F(DepthTextureTest, MAYBE_RenderTo) {
  if (!GLTestHelper::HasExtension("GL_CHROMIUM_depth_texture")) {
    return;
  }

  bool have_depth_stencil = GLTestHelper::HasExtension(
      "GL_OES_packed_depth_stencil");

  static const char* v_shader_str = SHADER(
      attribute vec4 v_position;
      void main()
      {
         gl_Position = v_position;
      }
  );
  static const char* f_shader_str = SHADER(
      precision mediump float;
      uniform sampler2D u_texture;
      uniform vec2 u_resolution;
      void main()
      {
        vec2 texcoord = gl_FragCoord.xy / u_resolution;
        gl_FragColor = texture2D(u_texture, texcoord);
      }
  );

  GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);

  GLint position_loc = glGetAttribLocation(program, "v_position");
  GLint resolution_loc = glGetUniformLocation(program, "u_resolution");

  SetupUnitQuad(position_loc);

  // Depth test needs to be on for the depth buffer to be updated.
  glEnable(GL_DEPTH_TEST);

  // create an fbo
  GLuint fbo = 0;
  glGenFramebuffers(1, &fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo);

  // create a depth texture.
  GLuint color_texture = 0;
  GLuint depth_texture = 0;

  glGenTextures(1, &color_texture);
  glBindTexture(GL_TEXTURE_2D, color_texture);
  glTexImage2D(
      GL_TEXTURE_2D, 0, GL_RGBA, kResolution, kResolution,
      0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glFramebufferTexture2D(
      GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0);

  glGenTextures(1, &depth_texture);
  glBindTexture(GL_TEXTURE_2D, depth_texture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glFramebufferTexture2D(
      GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);

  glUseProgram(program);
  glUniform2f(resolution_loc, kResolution, kResolution);

  static const FormatType format_types[] = {
    { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
    { GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
    { GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES },
  };
  for (size_t ii = 0; ii < arraysize(format_types); ++ii) {
    const FormatType& format_type = format_types[ii];
    GLenum format = format_type.format;
    GLenum type = format_type.type;

    if (format == GL_DEPTH_STENCIL_OES && !have_depth_stencil) {
      continue;
    }

    glBindTexture(GL_TEXTURE_2D, depth_texture);
    glTexImage2D(
        GL_TEXTURE_2D, 0, format, kResolution, kResolution,
        0, format, type, NULL);

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), status)
        << "iteration: " << ii;
    if (status != GL_FRAMEBUFFER_COMPLETE) {
      continue;
    }

    if (!GLTestHelper::CheckGLError("no errors after setup", __LINE__)) {
      continue;
    }

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Disconnect the texture so we'll render with the default texture.
    glBindTexture(GL_TEXTURE_2D, 0);

    // Render to the fbo.
    glDrawArrays(GL_TRIANGLES, 0, 6);

    if (!GLTestHelper::CheckGLError("no errors after depth draw", __LINE__)) {
      continue;
    }

    // Render with the depth texture.
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, depth_texture);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    if (!GLTestHelper::CheckGLError("no errors after texture draw", __LINE__)) {
      continue;
    }

    uint8 actual_pixels[kResolution * kResolution * 4] = { 0, };
    glReadPixels(
        0, 0, kResolution, kResolution, GL_RGBA, GL_UNSIGNED_BYTE,
        actual_pixels);

    if (!GLTestHelper::CheckGLError("no errors after readpixels", __LINE__)) {
      continue;
    }

    // Check that each pixel's RGB are the same and that it's value is less
    // than the previous pixel in either direction. Basically verify we have a
    // gradient.
    int bad_count = 0;  // used to not spam the log with too many messages.
    for (GLint yy = 0; bad_count < 16 && yy < kResolution; ++yy) {
      for (GLint xx = 0; bad_count < 16 && xx < kResolution; ++xx) {
        const uint8* actual = &actual_pixels[(yy * kResolution + xx) * 4];
        const uint8* left = actual - 4;
        const uint8* down = actual - kResolution * 4;

        EXPECT_EQ(actual[0], actual[1]) << "pixel at " << xx << ", " << yy;
        EXPECT_EQ(actual[1], actual[2]) << "pixel at " << xx << ", " << yy;
        bad_count += (actual[0] == actual[1] ? 0 : 1);

        // NOTE: Qualcomm on Nexus 4 the right most column has the same
        // values as the next to right most column. (bad interpolator?)
        if (xx > 0 && xx < kResolution - 1) {
          EXPECT_GT(actual[0], left[0])
              << "pixel at " << xx << ", " << yy
              << " actual[0] =" << static_cast<unsigned>(actual[0])
              << " left[0] =" << static_cast<unsigned>(left[0])
              << " actual =" << reinterpret_cast<const void*>(actual)
              << " left =" << reinterpret_cast<const void*>(left);
          bad_count += (actual[0] > left[0] ? 0 : 1);
        }

        if (yy > 0 && yy < kResolution - 1) {
          EXPECT_GT(actual[0], down[0]) << "pixel at " << xx << ", " << yy;
          bad_count += (actual[0] > down[0] ? 0 : 1);
        }

        EXPECT_TRUE(actual[3] == actual[0] || actual[3] == 0xFF)
            << "pixel at " << xx << ", " << yy;
        bad_count += ((actual[3] == actual[0] || actual[3] == 0xFF) ? 0 : 1);
      }
    }

    // Check that bottom left corner is vastly different thatn top right.
    EXPECT_GT(
        actual_pixels[(kResolution * kResolution - 1) * 4] - actual_pixels[0],
        0xC0);

    GLTestHelper::CheckGLError("no errors after everything", __LINE__);
  }
}

}  // namespace gpu

<commit_msg>Disable DepthTextureTest.RenderTo on all Windows platforms.<commit_after>// Copyright (c) 2012 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 <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#define SHADER(Src) #Src

namespace gpu {

class DepthTextureTest : public testing::Test {
 protected:
  static const GLsizei kResolution = 64;
  virtual void SetUp() {
    GLManager::Options options;
    options.size = gfx::Size(kResolution, kResolution);
    gl_.Initialize(options);
  }

  virtual void TearDown() {
    gl_.Destroy();
  }

  GLuint SetupUnitQuad(GLint position_location);

  GLManager gl_;
};

GLuint DepthTextureTest::SetupUnitQuad(GLint position_location) {
  GLuint vbo = 0;
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  static float vertices[] = {
      1.0f,  1.0f,  1.0f,
     -1.0f,  1.0f,  0.0f,
     -1.0f, -1.0f, -1.0f,
      1.0f,  1.0f,  1.0f,
     -1.0f, -1.0f, -1.0f,
      1.0f, -1.0f,  0.0f,
  };
  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  glEnableVertexAttribArray(position_location);
  glVertexAttribPointer(position_location, 3, GL_FLOAT, GL_FALSE, 0, 0);

  return vbo;
}

namespace {

struct FormatType {
  GLenum format;
  GLenum type;
};

}  // anonymous namespace

// crbug.com/135229
// Fails on all Windows platforms and on Linux Intel.
#if defined(OS_WIN) || (defined(OS_LINUX) && defined(NDEBUG))
#define MAYBE_RenderTo DISABLED_RenderTo
#else
#define MAYBE_RenderTo RenderTo
#endif

TEST_F(DepthTextureTest, MAYBE_RenderTo) {
  if (!GLTestHelper::HasExtension("GL_CHROMIUM_depth_texture")) {
    return;
  }

  bool have_depth_stencil = GLTestHelper::HasExtension(
      "GL_OES_packed_depth_stencil");

  static const char* v_shader_str = SHADER(
      attribute vec4 v_position;
      void main()
      {
         gl_Position = v_position;
      }
  );
  static const char* f_shader_str = SHADER(
      precision mediump float;
      uniform sampler2D u_texture;
      uniform vec2 u_resolution;
      void main()
      {
        vec2 texcoord = gl_FragCoord.xy / u_resolution;
        gl_FragColor = texture2D(u_texture, texcoord);
      }
  );

  GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);

  GLint position_loc = glGetAttribLocation(program, "v_position");
  GLint resolution_loc = glGetUniformLocation(program, "u_resolution");

  SetupUnitQuad(position_loc);

  // Depth test needs to be on for the depth buffer to be updated.
  glEnable(GL_DEPTH_TEST);

  // create an fbo
  GLuint fbo = 0;
  glGenFramebuffers(1, &fbo);
  glBindFramebuffer(GL_FRAMEBUFFER, fbo);

  // create a depth texture.
  GLuint color_texture = 0;
  GLuint depth_texture = 0;

  glGenTextures(1, &color_texture);
  glBindTexture(GL_TEXTURE_2D, color_texture);
  glTexImage2D(
      GL_TEXTURE_2D, 0, GL_RGBA, kResolution, kResolution,
      0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glFramebufferTexture2D(
      GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0);

  glGenTextures(1, &depth_texture);
  glBindTexture(GL_TEXTURE_2D, depth_texture);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glFramebufferTexture2D(
      GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);

  glUseProgram(program);
  glUniform2f(resolution_loc, kResolution, kResolution);

  static const FormatType format_types[] = {
    { GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT },
    { GL_DEPTH_COMPONENT, GL_UNSIGNED_INT },
    { GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES },
  };
  for (size_t ii = 0; ii < arraysize(format_types); ++ii) {
    const FormatType& format_type = format_types[ii];
    GLenum format = format_type.format;
    GLenum type = format_type.type;

    if (format == GL_DEPTH_STENCIL_OES && !have_depth_stencil) {
      continue;
    }

    glBindTexture(GL_TEXTURE_2D, depth_texture);
    glTexImage2D(
        GL_TEXTURE_2D, 0, format, kResolution, kResolution,
        0, format, type, NULL);

    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), status)
        << "iteration: " << ii;
    if (status != GL_FRAMEBUFFER_COMPLETE) {
      continue;
    }

    if (!GLTestHelper::CheckGLError("no errors after setup", __LINE__)) {
      continue;
    }

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Disconnect the texture so we'll render with the default texture.
    glBindTexture(GL_TEXTURE_2D, 0);

    // Render to the fbo.
    glDrawArrays(GL_TRIANGLES, 0, 6);

    if (!GLTestHelper::CheckGLError("no errors after depth draw", __LINE__)) {
      continue;
    }

    // Render with the depth texture.
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, depth_texture);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    if (!GLTestHelper::CheckGLError("no errors after texture draw", __LINE__)) {
      continue;
    }

    uint8 actual_pixels[kResolution * kResolution * 4] = { 0, };
    glReadPixels(
        0, 0, kResolution, kResolution, GL_RGBA, GL_UNSIGNED_BYTE,
        actual_pixels);

    if (!GLTestHelper::CheckGLError("no errors after readpixels", __LINE__)) {
      continue;
    }

    // Check that each pixel's RGB are the same and that it's value is less
    // than the previous pixel in either direction. Basically verify we have a
    // gradient.
    int bad_count = 0;  // used to not spam the log with too many messages.
    for (GLint yy = 0; bad_count < 16 && yy < kResolution; ++yy) {
      for (GLint xx = 0; bad_count < 16 && xx < kResolution; ++xx) {
        const uint8* actual = &actual_pixels[(yy * kResolution + xx) * 4];
        const uint8* left = actual - 4;
        const uint8* down = actual - kResolution * 4;

        EXPECT_EQ(actual[0], actual[1]) << "pixel at " << xx << ", " << yy;
        EXPECT_EQ(actual[1], actual[2]) << "pixel at " << xx << ", " << yy;
        bad_count += (actual[0] == actual[1] ? 0 : 1);

        // NOTE: Qualcomm on Nexus 4 the right most column has the same
        // values as the next to right most column. (bad interpolator?)
        if (xx > 0 && xx < kResolution - 1) {
          EXPECT_GT(actual[0], left[0])
              << "pixel at " << xx << ", " << yy
              << " actual[0] =" << static_cast<unsigned>(actual[0])
              << " left[0] =" << static_cast<unsigned>(left[0])
              << " actual =" << reinterpret_cast<const void*>(actual)
              << " left =" << reinterpret_cast<const void*>(left);
          bad_count += (actual[0] > left[0] ? 0 : 1);
        }

        if (yy > 0 && yy < kResolution - 1) {
          EXPECT_GT(actual[0], down[0]) << "pixel at " << xx << ", " << yy;
          bad_count += (actual[0] > down[0] ? 0 : 1);
        }

        EXPECT_TRUE(actual[3] == actual[0] || actual[3] == 0xFF)
            << "pixel at " << xx << ", " << yy;
        bad_count += ((actual[3] == actual[0] || actual[3] == 0xFF) ? 0 : 1);
      }
    }

    // Check that bottom left corner is vastly different thatn top right.
    EXPECT_GT(
        actual_pixels[(kResolution * kResolution - 1) * 4] - actual_pixels[0],
        0xC0);

    GLTestHelper::CheckGLError("no errors after everything", __LINE__);
  }
}

}  // namespace gpu

<|endoftext|>