<commit_before>/* Copyright 2017 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/core/grappler/grappler_item.h"

#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "tensorflow/core/framework/attr_value.pb.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/grappler/op_types.h"
#include "tensorflow/core/grappler/utils.h"

namespace tensorflow {
namespace grappler {

GrapplerItem::GrapplerItem(const GrapplerItem& other, GraphDef&& graphDef) {
  id = other.id;
  feed = other.feed;
  fetch = other.fetch;
  init_ops = other.init_ops;
  expected_init_time = other.expected_init_time;
  save_op = other.save_op;
  restore_op = other.restore_op;
  save_restore_loc_tensor = other.save_restore_loc_tensor;
  queue_runners = other.queue_runners;
  graph.Swap(&graphDef);
}

std::vector<const NodeDef*> GrapplerItem::MainOpsFanin() const {
  return ComputeTransitiveFanin(graph, fetch);
}

std::vector<const NodeDef*> GrapplerItem::EnqueueOpsFanin() const {
  std::vector<string> enqueue_ops;
  for (const auto& queue_runner : queue_runners) {
    for (const string& enqueue_op : queue_runner.enqueue_op_name()) {
      enqueue_ops.push_back(enqueue_op);
    }
  }
  return ComputeTransitiveFanin(graph, enqueue_ops);
}

std::vector<const NodeDef*> GrapplerItem::InitOpsFanin() const {
  return ComputeTransitiveFanin(graph, init_ops);
}

std::vector<const NodeDef*> GrapplerItem::MainVariables() const {
  std::vector<const NodeDef*> fanin = ComputeTransitiveFanin(graph, init_ops);
  std::vector<const NodeDef*> vars;
  for (const NodeDef* node : fanin) {
    if (IsVariable(*node)) {
      vars.push_back(node);
    }
  }
  return vars;
}

std::unordered_set<string> GrapplerItem::NodesToPreserve() const {
  std::unordered_set<string> result;
  for (const string& f : fetch) {
    VLOG(1) << "Add fetch " << f;
    result.insert(NodeName(f));
  }
  for (const auto& f : feed) {
    VLOG(1) << "Add feed " << f.first;
    result.insert(NodeName(f.first));
  }
  for (const auto& node : init_ops) {
    result.insert(NodeName(node));
  }
  if (!save_op.empty()) {
    result.insert(NodeName(save_op));
  }
  if (!restore_op.empty()) {
    result.insert(NodeName(restore_op));
  }
  if (!save_restore_loc_tensor.empty()) {
    result.insert(NodeName(save_restore_loc_tensor));
  }

  for (const auto& queue_runner : queue_runners) {
    for (const string& enqueue_op : queue_runner.enqueue_op_name()) {
      result.insert(NodeName(enqueue_op));
    }
    if (!queue_runner.close_op_name().empty()) {
      result.insert(NodeName(queue_runner.close_op_name()));
    }
    if (!queue_runner.cancel_op_name().empty()) {
      result.insert(NodeName(queue_runner.cancel_op_name()));
    }
  }
  return result;
}

std::vector<const NodeDef*> ComputeTransitiveFanin(
    const GraphDef& graph, const std::vector<string>& terminal_nodes) {
  bool ill_formed = false;
  std::vector<const NodeDef*> result =
      ComputeTransitiveFanin(graph, terminal_nodes, &ill_formed);
  CHECK(!ill_formed);
  return result;
}

std::vector<const NodeDef*> ComputeTransitiveFanin(
    const GraphDef& graph, const std::vector<string>& terminal_nodes,
    bool* ill_formed) {
  *ill_formed = false;
  std::unordered_map<string, const NodeDef*> name_to_node;
  std::unordered_map<string, const NodeDef*> name_to_send;
  for (const auto& node : graph.node()) {
    name_to_node[node.name()] = &node;
    if (node.op() == "_Send") {
      const auto& attr = node.attr();
      name_to_send[attr.at("tensor_name").s()] = &node;
    }
  }

  std::vector<const NodeDef*> queue;
  for (const string& root : terminal_nodes) {
    const NodeDef* node = name_to_node[NodeName(root)];
    if (!node) {
      *ill_formed = true;
      return {};
    }
    queue.push_back(node);
  }

  std::vector<const NodeDef*> result;
  std::unordered_set<const NodeDef*> visited;

  while (!queue.empty()) {
    const NodeDef* node = queue.back();
    queue.pop_back();
    if (!visited.insert(node).second) {
      // The node has already been visited.
      continue;
    }
    result.push_back(node);
    for (const string& input : node->input()) {
      const NodeDef* in = name_to_node[NodeName(input)];
      if (!in) {
        *ill_formed = true;
        return {};
      }
      queue.push_back(in);
    }
    if (node->op() == "_Recv") {
      const auto& attr = node->attr();
      const NodeDef* send = name_to_send[attr.at("tensor_name").s()];
      if (send) {
        queue.push_back(send);
      }
      // Subgraph after partitioning may have either _Send or _Recv, not both.
      // So, we do not set ill_formed for missing _Send.
    }
  }
  return result;
}

}  // end namespace grappler
}  // end namespace tensorflow
<commit_msg>Log more info about the ill-formed node in ComputeTransitiveFanin.<commit_after>/* Copyright 2017 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/core/grappler/grappler_item.h"

#include <unordered_map>
#include <unordered_set>
#include <vector>

#include "tensorflow/core/framework/attr_value.pb.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/grappler/op_types.h"
#include "tensorflow/core/grappler/utils.h"

namespace tensorflow {
namespace grappler {

GrapplerItem::GrapplerItem(const GrapplerItem& other, GraphDef&& graphDef) {
  id = other.id;
  feed = other.feed;
  fetch = other.fetch;
  init_ops = other.init_ops;
  expected_init_time = other.expected_init_time;
  save_op = other.save_op;
  restore_op = other.restore_op;
  save_restore_loc_tensor = other.save_restore_loc_tensor;
  queue_runners = other.queue_runners;
  graph.Swap(&graphDef);
}

std::vector<const NodeDef*> GrapplerItem::MainOpsFanin() const {
  return ComputeTransitiveFanin(graph, fetch);
}

std::vector<const NodeDef*> GrapplerItem::EnqueueOpsFanin() const {
  std::vector<string> enqueue_ops;
  for (const auto& queue_runner : queue_runners) {
    for (const string& enqueue_op : queue_runner.enqueue_op_name()) {
      enqueue_ops.push_back(enqueue_op);
    }
  }
  return ComputeTransitiveFanin(graph, enqueue_ops);
}

std::vector<const NodeDef*> GrapplerItem::InitOpsFanin() const {
  return ComputeTransitiveFanin(graph, init_ops);
}

std::vector<const NodeDef*> GrapplerItem::MainVariables() const {
  std::vector<const NodeDef*> fanin = ComputeTransitiveFanin(graph, init_ops);
  std::vector<const NodeDef*> vars;
  for (const NodeDef* node : fanin) {
    if (IsVariable(*node)) {
      vars.push_back(node);
    }
  }
  return vars;
}

std::unordered_set<string> GrapplerItem::NodesToPreserve() const {
  std::unordered_set<string> result;
  for (const string& f : fetch) {
    VLOG(1) << "Add fetch " << f;
    result.insert(NodeName(f));
  }
  for (const auto& f : feed) {
    VLOG(1) << "Add feed " << f.first;
    result.insert(NodeName(f.first));
  }
  for (const auto& node : init_ops) {
    result.insert(NodeName(node));
  }
  if (!save_op.empty()) {
    result.insert(NodeName(save_op));
  }
  if (!restore_op.empty()) {
    result.insert(NodeName(restore_op));
  }
  if (!save_restore_loc_tensor.empty()) {
    result.insert(NodeName(save_restore_loc_tensor));
  }

  for (const auto& queue_runner : queue_runners) {
    for (const string& enqueue_op : queue_runner.enqueue_op_name()) {
      result.insert(NodeName(enqueue_op));
    }
    if (!queue_runner.close_op_name().empty()) {
      result.insert(NodeName(queue_runner.close_op_name()));
    }
    if (!queue_runner.cancel_op_name().empty()) {
      result.insert(NodeName(queue_runner.cancel_op_name()));
    }
  }
  return result;
}

std::vector<const NodeDef*> ComputeTransitiveFanin(
    const GraphDef& graph, const std::vector<string>& terminal_nodes) {
  bool ill_formed = false;
  std::vector<const NodeDef*> result =
      ComputeTransitiveFanin(graph, terminal_nodes, &ill_formed);
  CHECK(!ill_formed);
  return result;
}

std::vector<const NodeDef*> ComputeTransitiveFanin(
    const GraphDef& graph, const std::vector<string>& terminal_nodes,
    bool* ill_formed) {
  *ill_formed = false;
  std::unordered_map<string, const NodeDef*> name_to_node;
  std::unordered_map<string, const NodeDef*> name_to_send;
  for (const auto& node : graph.node()) {
    name_to_node[node.name()] = &node;
    if (node.op() == "_Send") {
      const auto& attr = node.attr();
      name_to_send[attr.at("tensor_name").s()] = &node;
    }
  }

  std::vector<const NodeDef*> queue;
  for (const string& root : terminal_nodes) {
    const NodeDef* node = name_to_node[NodeName(root)];
    if (!node) {
      *ill_formed = true;
      VLOG(2) << "ComputeTransitiveFanin: problem with root node: " << root;
      return {};
    }
    queue.push_back(node);
  }

  std::vector<const NodeDef*> result;
  std::unordered_set<const NodeDef*> visited;

  while (!queue.empty()) {
    const NodeDef* node = queue.back();
    queue.pop_back();
    if (!visited.insert(node).second) {
      // The node has already been visited.
      continue;
    }
    result.push_back(node);
    for (const string& input : node->input()) {
      const NodeDef* in = name_to_node[NodeName(input)];
      if (!in) {
        VLOG(2) << "ComputeTransitiveFanin: problem with node: " << input;
        *ill_formed = true;
        return {};
      }
      queue.push_back(in);
    }
    if (node->op() == "_Recv") {
      const auto& attr = node->attr();
      const NodeDef* send = name_to_send[attr.at("tensor_name").s()];
      if (send) {
        queue.push_back(send);
      }
      // Subgraph after partitioning may have either _Send or _Recv, not both.
      // So, we do not set ill_formed for missing _Send.
    }
  }
  return result;
}

}  // end namespace grappler
}  // end namespace tensorflow
<|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/python/util/kernel_registry.h"

#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/node_def_util.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/util/device_name_utils.h"

namespace tensorflow {
namespace swig {

string TryFindKernelClass(const string& serialized_node_def) {
  tensorflow::NodeDef node_def;
  if (!node_def.ParseFromString(serialized_node_def)) {
    LOG(WARNING) << "Error parsing node_def";
    return "";
  }

  const tensorflow::OpRegistrationData* op_reg_data;
  auto status =
      tensorflow::OpRegistry::Global()->LookUp(node_def.op(), &op_reg_data);
  if (!status.ok()) {
    LOG(WARNING) << "Op " << node_def.op() << " not found: " << status;
    return "";
  }
  AddDefaultsToNodeDef(op_reg_data->op_def, &node_def);

  tensorflow::DeviceNameUtils::ParsedName parsed_name;
  if (!tensorflow::DeviceNameUtils::ParseFullName(node_def.device(),
                                                  &parsed_name)) {
    LOG(WARNING) << "Failed to parse device from node_def: "
                 << node_def.ShortDebugString();
    return "";
  }
  string class_name = "";
  tensorflow::FindKernelDef(tensorflow::DeviceType(parsed_name.type.c_str()),
                            node_def, nullptr /* kernel_def */, &class_name)
      .IgnoreError();
  return class_name;
}

}  // namespace swig
}  // namespace tensorflow
<commit_msg>Log a warning instead of silently ignoring errors during kernel lookup.<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/python/util/kernel_registry.h"

#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/node_def_util.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/util/device_name_utils.h"

namespace tensorflow {
namespace swig {

string TryFindKernelClass(const string& serialized_node_def) {
  tensorflow::NodeDef node_def;
  if (!node_def.ParseFromString(serialized_node_def)) {
    LOG(WARNING) << "Error parsing node_def";
    return "";
  }

  const tensorflow::OpRegistrationData* op_reg_data;
  auto status =
      tensorflow::OpRegistry::Global()->LookUp(node_def.op(), &op_reg_data);
  if (!status.ok()) {
    LOG(WARNING) << "Op " << node_def.op() << " not found: " << status;
    return "";
  }
  AddDefaultsToNodeDef(op_reg_data->op_def, &node_def);

  tensorflow::DeviceNameUtils::ParsedName parsed_name;
  if (!tensorflow::DeviceNameUtils::ParseFullName(node_def.device(),
                                                  &parsed_name)) {
    LOG(WARNING) << "Failed to parse device from node_def: "
                 << node_def.ShortDebugString();
    return "";
  }
  string class_name = "";
  status = tensorflow::FindKernelDef(
      tensorflow::DeviceType(parsed_name.type.c_str()), node_def,
      nullptr /* kernel_def */, &class_name);
  if (!status.ok()) {
    LOG(WARNING) << "Op [" << node_def.op() << "]: " << status;
  }
  return class_name;
}

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


<commit_before>#ifndef __WRAPPER_DOMAIN_HH__
#define __WRAPPER_DOMAIN_HH__

#include "crab_llvm/config.h"
#include "crab_llvm/crab_domains.hh"

/**
 *  Definition of a generic wrapper class (for crab-llvm clients) to
 *  contain an arbitrary abstract domain.
 *
 *  A crab-llvm client should only access to:
 *  - class GenericAbsDomWrapper and its public methods.
 *  - getAbsDomWrappee to get the underlying domain from an
 *    GenericAbsDomWrapper object.
*/

namespace llvm {

  #define DUMP_TO_LLVM_STREAM(T)  \
  inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o, \
                                       T& e) {               \
    crab::crab_string_os s;                                  \
    s << e;                                                  \
    o << s.str ();                                           \
    return o; }

  DUMP_TO_LLVM_STREAM(crab_llvm::lin_exp_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::lin_cst_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::lin_cst_sys_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::interval_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::wrapped_interval_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::ric_domain_t)
  //DUMP_TO_LLVM_STREAM(crab_llvm::dbm_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::split_dbm_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::boxes_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::dis_interval_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::num_domain_t)

  template <typename DomInfo>
  inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o,
                                       crab::domains::term_domain<DomInfo>& inv) {
    crab::crab_string_os s;
    s << inv;
    o << s.str ();
    return o;
  }

  template <typename N, typename V, crab::domains::apron_domain_id_t D>
  inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o,
				       crab::domains::apron_domain
				       <N,V,D> & inv) {
    crab::crab_string_os s;
    s << inv;
    o << s.str ();
    return o;
  }

  template <typename Base>
  inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o,
				       crab::domains::array_smashing <Base> & inv) {
    crab::crab_string_os s;
    s << inv;
    o << s.str ();
    return o;
  }

} // end namespace llvm

namespace crab_llvm {

   //////
   /// Definition of macros
   //////

   #define DEFINE_WRAPPER(WRAPPER,ABS_DOM,ID)                        \
   class WRAPPER: public GenericAbsDomWrapper {                      \
     id_t m_id;                                                      \
     ABS_DOM m_abs;                                                  \
    public:                                                          \
     id_t getId () const { return m_id;}                             \
       								     \
     WRAPPER (ABS_DOM abs, id_t id):                                 \
       GenericAbsDomWrapper(), m_id(id), m_abs(abs) { }		     \
  								     \
     WRAPPER (ABS_DOM abs):                                          \
       GenericAbsDomWrapper(), m_id (ID), m_abs (abs) { }	     \
                                                                     \
     GenericAbsDomWrapperPtr clone() const {                         \
       auto res = boost::make_shared<WRAPPER>(m_abs, m_id); 	     \
       return res;                                                   \
     }                                                               \
                                                                     \
     ABS_DOM& get() { return m_abs; }                                \
                                                                     \
     lin_cst_sys_t to_linear_constraints() {			     \
       return m_abs.to_linear_constraint_system();                   \
     }                                                               \
                                                                     \
     void write (crab::crab_os& o) {                                 \
       m_abs.write (o);                                              \
     }                                                               \
                                                                     \
     void forget (const std::vector<var_t>& vars) {		     \
       crab::domains::domain_traits<ABS_DOM>::forget (m_abs,         \
                                                      vars.begin (), \
                                                      vars.end ());  \
     }                                                               \
   };                                                                \
                                                                     \
   template <> inline GenericAbsDomWrapperPtr                        \
   mkGenericAbsDomWrapper (ABS_DOM abs_dom) {                        \
     GenericAbsDomWrapperPtr res (new WRAPPER(abs_dom));             \
     return res;                                                     \
   }                                                                 \
                                                                     \
   template <>                                                       \
   inline void getAbsDomWrappee (GenericAbsDomWrapperPtr wrapper,    \
                                 ABS_DOM &abs_dom) {                 \
     auto wrappee = boost::dynamic_pointer_cast<WRAPPER> (wrapper);  \
     if (!wrappee) {                                                 \
       CRAB_ERROR("Could not cast wrapper to an instance of ",       \
                  ABS_DOM::getDomainName ());                        \
     }                                                               \
     abs_dom = wrappee->get ();                                      \
   }

  //////
  // Generic wrapper to encapsulate an arbitrary abstract domain
  //////

  struct GenericAbsDomWrapper {

    typedef boost::shared_ptr<GenericAbsDomWrapper> GenericAbsDomWrapperPtr;

    typedef enum { intv, /*dbm,*/ split_dbm,
		   term_intv, term_dis_intv,
		   ric,
		   boxes, dis_intv,
		   opt_oct_apron, pk_apron,
		   num,
		   w_intv, w_split_dbm, w_opt_oct_apron, w_pk_apron} id_t;

    GenericAbsDomWrapper() { }

    virtual ~GenericAbsDomWrapper() { }

    virtual id_t getId() const = 0;

    virtual GenericAbsDomWrapperPtr clone() const = 0;

    virtual void write(crab::crab_os& o) = 0;

    virtual lin_cst_sys_t to_linear_constraints() = 0;

    virtual void forget(const std::vector<var_t>& vars) = 0;
   };

   typedef GenericAbsDomWrapper::GenericAbsDomWrapperPtr GenericAbsDomWrapperPtr;

   inline crab::crab_os& operator<<(crab::crab_os& o ,
                                    const GenericAbsDomWrapperPtr& v) {
     v->write (o);
     return o;
   }

   inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o ,
                                        const GenericAbsDomWrapperPtr& v) {
     crab::crab_string_os s;
     v->write (s);
     o << s.str ();
     return o;
   }

   // Internal crab-llvm use: convert a crab domain into wrapper
   template <typename T>
   inline GenericAbsDomWrapperPtr mkGenericAbsDomWrapper (T abs_dom);

   // For crab-llvm clients: convert a wrapper into the underlying crab domain
   template <typename T>
   inline void getAbsDomWrappee (GenericAbsDomWrapperPtr wrapper, T& wrappee);

   DEFINE_WRAPPER(IntervalDomainWrapper,interval_domain_t,intv)
   DEFINE_WRAPPER(WrappedIntervalDomainWrapper,wrapped_interval_domain_t,w_intv)
   DEFINE_WRAPPER(RicDomainWrapper,ric_domain_t,ric)
   //DEFINE_WRAPPER(DbmDomainWrapper,dbm_domain_t,dbm)
   DEFINE_WRAPPER(SDbmDomainWrapper,split_dbm_domain_t,split_dbm)
   DEFINE_WRAPPER(TermIntDomainWrapper,term_int_domain_t,term_intv)
   DEFINE_WRAPPER(TermDisIntDomainWrapper,term_dis_int_domain_t,term_dis_intv)
   DEFINE_WRAPPER(BoxesDomainWrapper,boxes_domain_t,boxes)
   DEFINE_WRAPPER(DisIntervalDomainWrapper,dis_interval_domain_t,dis_intv)
   DEFINE_WRAPPER(OptOctApronDomainWrapper,opt_oct_apron_domain_t,opt_oct_apron)
   DEFINE_WRAPPER(PkApronDomainWrapper,pk_apron_domain_t,pk_apron)
   DEFINE_WRAPPER(NumDomainWrapper,num_domain_t,num)

} // end namespace crab_llvm

#endif
<commit_msg>Add project operation to GenericAbsDomWrapper<commit_after>#ifndef __WRAPPER_DOMAIN_HH__
#define __WRAPPER_DOMAIN_HH__

#include "crab_llvm/config.h"
#include "crab_llvm/crab_domains.hh"

/**
 *  Definition of a generic wrapper class (for crab-llvm clients) to
 *  contain an arbitrary abstract domain.
 *
 *  A crab-llvm client should only access to:
 *  - class GenericAbsDomWrapper and its public methods.
 *  - getAbsDomWrappee to get the underlying domain from an
 *    GenericAbsDomWrapper object.
*/

namespace llvm {

  #define DUMP_TO_LLVM_STREAM(T)  \
  inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o, \
                                       T& e) {               \
    crab::crab_string_os s;                                  \
    s << e;                                                  \
    o << s.str ();                                           \
    return o; }

  DUMP_TO_LLVM_STREAM(crab_llvm::lin_exp_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::lin_cst_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::lin_cst_sys_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::interval_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::wrapped_interval_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::ric_domain_t)
  //DUMP_TO_LLVM_STREAM(crab_llvm::dbm_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::split_dbm_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::boxes_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::dis_interval_domain_t)
  DUMP_TO_LLVM_STREAM(crab_llvm::num_domain_t)

  template <typename DomInfo>
  inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o,
                                       crab::domains::term_domain<DomInfo>& inv) {
    crab::crab_string_os s;
    s << inv;
    o << s.str ();
    return o;
  }

  template <typename N, typename V, crab::domains::apron_domain_id_t D>
  inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o,
				       crab::domains::apron_domain
				       <N,V,D> & inv) {
    crab::crab_string_os s;
    s << inv;
    o << s.str ();
    return o;
  }

  template <typename Base>
  inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o,
				       crab::domains::array_smashing <Base> & inv) {
    crab::crab_string_os s;
    s << inv;
    o << s.str ();
    return o;
  }

} // end namespace llvm

namespace crab_llvm {

   //////
   /// Definition of macros
   //////

   #define DEFINE_WRAPPER(WRAPPER,ABS_DOM,ID)                        \
   class WRAPPER: public GenericAbsDomWrapper {                      \
     id_t m_id;                                                      \
     ABS_DOM m_abs;                                                  \
    public:                                                          \
    id_t getId() const { return m_id;}				     \
    								     \
    WRAPPER(ABS_DOM abs, id_t id):				     \
      GenericAbsDomWrapper(), m_id(id), m_abs(abs) { }		     \
    								     \
    WRAPPER(ABS_DOM abs):					     \
      GenericAbsDomWrapper(), m_id (ID), m_abs (abs) { }	     \
    								     \
    GenericAbsDomWrapperPtr clone() const {			     \
      auto res = boost::make_shared<WRAPPER>(m_abs, m_id); 	     \
      return res;						     \
    }								     \
    								     \
    ABS_DOM& get() { return m_abs; }				     \
    								     \
    lin_cst_sys_t to_linear_constraints() {			     \
      return m_abs.to_linear_constraint_system();		     \
    }								     \
    								     \
    void write(crab::crab_os& o) {				     \
      m_abs.write (o);						     \
    }								     \
    								     \
    void forget(const std::vector<var_t>& vars) {		     \
      crab::domains::domain_traits<ABS_DOM>::forget(m_abs,	     \
						    vars.begin(),    \
						    vars.end());     \
    }								     \
    								     \
    void project(const std::vector<var_t>& vars) {		     \
       crab::domains::domain_traits<ABS_DOM>::project(m_abs,         \
                                                      vars.begin(),  \
                                                      vars.end());   \
    }								     \
    								     \
   };                                                                \
                                                                     \
   template <> inline GenericAbsDomWrapperPtr                        \
   mkGenericAbsDomWrapper (ABS_DOM abs_dom) {                        \
     GenericAbsDomWrapperPtr res (new WRAPPER(abs_dom));             \
     return res;                                                     \
   }                                                                 \
                                                                     \
   template <>                                                       \
   inline void getAbsDomWrappee (GenericAbsDomWrapperPtr wrapper,    \
                                 ABS_DOM &abs_dom) {                 \
     auto wrappee = boost::dynamic_pointer_cast<WRAPPER> (wrapper);  \
     if (!wrappee) {                                                 \
       CRAB_ERROR("Could not cast wrapper to an instance of ",       \
                  ABS_DOM::getDomainName ());                        \
     }                                                               \
     abs_dom = wrappee->get ();                                      \
   }

  //////
  // Generic wrapper to encapsulate an arbitrary abstract domain
  //////

  struct GenericAbsDomWrapper {

    typedef boost::shared_ptr<GenericAbsDomWrapper> GenericAbsDomWrapperPtr;

    typedef enum { intv, /*dbm,*/ split_dbm,
		   term_intv, term_dis_intv,
		   ric,
		   boxes, dis_intv,
		   opt_oct_apron, pk_apron,
		   num,
		   w_intv, w_split_dbm, w_opt_oct_apron, w_pk_apron} id_t;

    GenericAbsDomWrapper() { }

    virtual ~GenericAbsDomWrapper() { }

    virtual id_t getId() const = 0;

    virtual GenericAbsDomWrapperPtr clone() const = 0;

    virtual void write(crab::crab_os& o) = 0;

    virtual lin_cst_sys_t to_linear_constraints() = 0;

    virtual void forget(const std::vector<var_t>& vars) = 0;

    virtual void project(const std::vector<var_t>& vars) = 0;
   };

   typedef GenericAbsDomWrapper::GenericAbsDomWrapperPtr GenericAbsDomWrapperPtr;

   inline crab::crab_os& operator<<(crab::crab_os& o ,
                                    const GenericAbsDomWrapperPtr& v) {
     v->write (o);
     return o;
   }

   inline llvm::raw_ostream& operator<<(llvm::raw_ostream& o ,
                                        const GenericAbsDomWrapperPtr& v) {
     crab::crab_string_os s;
     v->write (s);
     o << s.str ();
     return o;
   }

   // Internal crab-llvm use: convert a crab domain into wrapper
   template <typename T>
   inline GenericAbsDomWrapperPtr mkGenericAbsDomWrapper (T abs_dom);

   // For crab-llvm clients: convert a wrapper into the underlying crab domain
   template <typename T>
   inline void getAbsDomWrappee (GenericAbsDomWrapperPtr wrapper, T& wrappee);

   DEFINE_WRAPPER(IntervalDomainWrapper,interval_domain_t,intv)
   DEFINE_WRAPPER(WrappedIntervalDomainWrapper,wrapped_interval_domain_t,w_intv)
   DEFINE_WRAPPER(RicDomainWrapper,ric_domain_t,ric)
   //DEFINE_WRAPPER(DbmDomainWrapper,dbm_domain_t,dbm)
   DEFINE_WRAPPER(SDbmDomainWrapper,split_dbm_domain_t,split_dbm)
   DEFINE_WRAPPER(TermIntDomainWrapper,term_int_domain_t,term_intv)
   DEFINE_WRAPPER(TermDisIntDomainWrapper,term_dis_int_domain_t,term_dis_intv)
   DEFINE_WRAPPER(BoxesDomainWrapper,boxes_domain_t,boxes)
   DEFINE_WRAPPER(DisIntervalDomainWrapper,dis_interval_domain_t,dis_intv)
   DEFINE_WRAPPER(OptOctApronDomainWrapper,opt_oct_apron_domain_t,opt_oct_apron)
   DEFINE_WRAPPER(PkApronDomainWrapper,pk_apron_domain_t,pk_apron)
   DEFINE_WRAPPER(NumDomainWrapper,num_domain_t,num)

} // end namespace crab_llvm

#endif
<|endoftext|>


<commit_before>//===------------------------ CalcSpillWeights.cpp ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "calcspillweights"

#include "llvm/Function.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/CodeGen/CalcSpillWeights.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;

char CalculateSpillWeights::ID = 0;
INITIALIZE_PASS_BEGIN(CalculateSpillWeights, "calcspillweights",
                "Calculate spill weights", false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_END(CalculateSpillWeights, "calcspillweights",
                "Calculate spill weights", false, false)

void CalculateSpillWeights::getAnalysisUsage(AnalysisUsage &au) const {
  au.addRequired<LiveIntervals>();
  au.addRequired<MachineLoopInfo>();
  au.setPreservesAll();
  MachineFunctionPass::getAnalysisUsage(au);
}

bool CalculateSpillWeights::runOnMachineFunction(MachineFunction &fn) {

  DEBUG(dbgs() << "********** Compute Spill Weights **********\n"
               << "********** Function: "
               << fn.getFunction()->getName() << '\n');

  LiveIntervals &lis = getAnalysis<LiveIntervals>();
  VirtRegAuxInfo vrai(fn, lis, getAnalysis<MachineLoopInfo>());
  for (LiveIntervals::iterator I = lis.begin(), E = lis.end(); I != E; ++I) {
    LiveInterval &li = *I->second;
    if (TargetRegisterInfo::isVirtualRegister(li.reg))
      vrai.CalculateWeightAndHint(li);
  }
  return false;
}

// Return the preferred allocation register for reg, given a COPY instruction.
static unsigned copyHint(const MachineInstr *mi, unsigned reg,
                         const TargetRegisterInfo &tri,
                         const MachineRegisterInfo &mri) {
  unsigned sub, hreg, hsub;
  if (mi->getOperand(0).getReg() == reg) {
    sub = mi->getOperand(0).getSubReg();
    hreg = mi->getOperand(1).getReg();
    hsub = mi->getOperand(1).getSubReg();
  } else {
    sub = mi->getOperand(1).getSubReg();
    hreg = mi->getOperand(0).getReg();
    hsub = mi->getOperand(0).getSubReg();
  }

  if (!hreg)
    return 0;

  if (TargetRegisterInfo::isVirtualRegister(hreg))
    return sub == hsub ? hreg : 0;

  const TargetRegisterClass *rc = mri.getRegClass(reg);

  // Only allow physreg hints in rc.
  if (sub == 0)
    return rc->contains(hreg) ? hreg : 0;

  // reg:sub should match the physreg hreg.
  return tri.getMatchingSuperReg(hreg, sub, rc);
}

void VirtRegAuxInfo::CalculateWeightAndHint(LiveInterval &li) {
  MachineRegisterInfo &mri = MF.getRegInfo();
  const TargetRegisterInfo &tri = *MF.getTarget().getRegisterInfo();
  MachineBasicBlock *mbb = 0;
  MachineLoop *loop = 0;
  unsigned loopDepth = 0;
  bool isExiting = false;
  float totalWeight = 0;
  SmallPtrSet<MachineInstr*, 8> visited;

  // Find the best physreg hist and the best virtreg hint.
  float bestPhys = 0, bestVirt = 0;
  unsigned hintPhys = 0, hintVirt = 0;

  // Don't recompute a target specific hint.
  bool noHint = mri.getRegAllocationHint(li.reg).first != 0;

  // Don't recompute spill weight for an unspillable register.
  bool Spillable = li.isSpillable();

  for (MachineRegisterInfo::reg_iterator I = mri.reg_begin(li.reg);
       MachineInstr *mi = I.skipInstruction();) {
    if (mi->isIdentityCopy() || mi->isImplicitDef() || mi->isDebugValue())
      continue;
    if (!visited.insert(mi))
      continue;

    float weight = 1.0f;
    if (Spillable) {
      // Get loop info for mi.
      if (mi->getParent() != mbb) {
        mbb = mi->getParent();
        loop = Loops.getLoopFor(mbb);
        loopDepth = loop ? loop->getLoopDepth() : 0;
        isExiting = loop ? loop->isLoopExiting(mbb) : false;
      }

      // Calculate instr weight.
      bool reads, writes;
      tie(reads, writes) = mi->readsWritesVirtualRegister(li.reg);
      weight = LiveIntervals::getSpillWeight(writes, reads, loopDepth);

      // Give extra weight to what looks like a loop induction variable update.
      if (writes && isExiting && LIS.isLiveOutOfMBB(li, mbb))
        weight *= 3;

      totalWeight += weight;
    }

    // Get allocation hints from copies.
    if (noHint || !mi->isCopy())
      continue;
    unsigned hint = copyHint(mi, li.reg, tri, mri);
    if (!hint)
      continue;
    float hweight = Hint[hint] += weight;
    if (TargetRegisterInfo::isPhysicalRegister(hint)) {
      if (hweight > bestPhys && LIS.isAllocatable(hint))
        bestPhys = hweight, hintPhys = hint;
    } else {
      if (hweight > bestVirt)
        bestVirt = hweight, hintVirt = hint;
    }
  }

  Hint.clear();

  // Always prefer the physreg hint.
  if (unsigned hint = hintPhys ? hintPhys : hintVirt) {
    mri.setRegAllocationHint(li.reg, 0, hint);
    // Weakly boost the spill weight of hinted registers.
    totalWeight *= 1.01F;
  }

  // If the live interval was already unspillable, leave it that way.
  if (!Spillable)
    return;

  // Mark li as unspillable if all live ranges are tiny.
  if (li.isZeroLength(LIS.getSlotIndexes())) {
    li.markNotSpillable();
    return;
  }

  // If all of the definitions of the interval are re-materializable,
  // it is a preferred candidate for spilling. If none of the defs are
  // loads, then it's potentially very cheap to re-materialize.
  // FIXME: this gets much more complicated once we support non-trivial
  // re-materialization.
  bool isLoad = false;
  if (LIS.isReMaterializable(li, 0, isLoad)) {
    if (isLoad)
      totalWeight *= 0.9F;
    else
      totalWeight *= 0.5F;
  }

  li.weight = normalizeSpillWeight(totalWeight, li.getSize());
}

void VirtRegAuxInfo::CalculateRegClass(unsigned reg) {
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const TargetInstrInfo *TII = MF.getTarget().getInstrInfo();
  const TargetRegisterInfo *TRI = MF.getTarget().getRegisterInfo();
  const TargetRegisterClass *OldRC = MRI.getRegClass(reg);
  const TargetRegisterClass *NewRC = TRI->getLargestLegalSuperClass(OldRC);

  // Stop early if there is no room to grow.
  if (NewRC == OldRC)
    return;

  // Accumulate constraints from all uses.
  for (MachineRegisterInfo::reg_nodbg_iterator I = MRI.reg_nodbg_begin(reg),
       E = MRI.reg_nodbg_end(); I != E; ++I) {
    // TRI doesn't have accurate enough information to model this yet.
    if (I.getOperand().getSubReg())
      return;
    const TargetRegisterClass *OpRC =
      TII->getRegClass(I->getDesc(), I.getOperandNo(), TRI);
    if (OpRC)
      NewRC = getCommonSubClass(NewRC, OpRC);
    if (!NewRC || NewRC == OldRC)
      return;
  }
  DEBUG(dbgs() << "Inflating " << OldRC->getName() << ':' << PrintReg(reg)
               << " to " << NewRC->getName() <<".\n");
  MRI.setRegClass(reg, NewRC);
}
<commit_msg>Don't inflate register classes used by inline asm.<commit_after>//===------------------------ CalcSpillWeights.cpp ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "calcspillweights"

#include "llvm/Function.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/CodeGen/CalcSpillWeights.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
using namespace llvm;

char CalculateSpillWeights::ID = 0;
INITIALIZE_PASS_BEGIN(CalculateSpillWeights, "calcspillweights",
                "Calculate spill weights", false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_END(CalculateSpillWeights, "calcspillweights",
                "Calculate spill weights", false, false)

void CalculateSpillWeights::getAnalysisUsage(AnalysisUsage &au) const {
  au.addRequired<LiveIntervals>();
  au.addRequired<MachineLoopInfo>();
  au.setPreservesAll();
  MachineFunctionPass::getAnalysisUsage(au);
}

bool CalculateSpillWeights::runOnMachineFunction(MachineFunction &fn) {

  DEBUG(dbgs() << "********** Compute Spill Weights **********\n"
               << "********** Function: "
               << fn.getFunction()->getName() << '\n');

  LiveIntervals &lis = getAnalysis<LiveIntervals>();
  VirtRegAuxInfo vrai(fn, lis, getAnalysis<MachineLoopInfo>());
  for (LiveIntervals::iterator I = lis.begin(), E = lis.end(); I != E; ++I) {
    LiveInterval &li = *I->second;
    if (TargetRegisterInfo::isVirtualRegister(li.reg))
      vrai.CalculateWeightAndHint(li);
  }
  return false;
}

// Return the preferred allocation register for reg, given a COPY instruction.
static unsigned copyHint(const MachineInstr *mi, unsigned reg,
                         const TargetRegisterInfo &tri,
                         const MachineRegisterInfo &mri) {
  unsigned sub, hreg, hsub;
  if (mi->getOperand(0).getReg() == reg) {
    sub = mi->getOperand(0).getSubReg();
    hreg = mi->getOperand(1).getReg();
    hsub = mi->getOperand(1).getSubReg();
  } else {
    sub = mi->getOperand(1).getSubReg();
    hreg = mi->getOperand(0).getReg();
    hsub = mi->getOperand(0).getSubReg();
  }

  if (!hreg)
    return 0;

  if (TargetRegisterInfo::isVirtualRegister(hreg))
    return sub == hsub ? hreg : 0;

  const TargetRegisterClass *rc = mri.getRegClass(reg);

  // Only allow physreg hints in rc.
  if (sub == 0)
    return rc->contains(hreg) ? hreg : 0;

  // reg:sub should match the physreg hreg.
  return tri.getMatchingSuperReg(hreg, sub, rc);
}

void VirtRegAuxInfo::CalculateWeightAndHint(LiveInterval &li) {
  MachineRegisterInfo &mri = MF.getRegInfo();
  const TargetRegisterInfo &tri = *MF.getTarget().getRegisterInfo();
  MachineBasicBlock *mbb = 0;
  MachineLoop *loop = 0;
  unsigned loopDepth = 0;
  bool isExiting = false;
  float totalWeight = 0;
  SmallPtrSet<MachineInstr*, 8> visited;

  // Find the best physreg hist and the best virtreg hint.
  float bestPhys = 0, bestVirt = 0;
  unsigned hintPhys = 0, hintVirt = 0;

  // Don't recompute a target specific hint.
  bool noHint = mri.getRegAllocationHint(li.reg).first != 0;

  // Don't recompute spill weight for an unspillable register.
  bool Spillable = li.isSpillable();

  for (MachineRegisterInfo::reg_iterator I = mri.reg_begin(li.reg);
       MachineInstr *mi = I.skipInstruction();) {
    if (mi->isIdentityCopy() || mi->isImplicitDef() || mi->isDebugValue())
      continue;
    if (!visited.insert(mi))
      continue;

    float weight = 1.0f;
    if (Spillable) {
      // Get loop info for mi.
      if (mi->getParent() != mbb) {
        mbb = mi->getParent();
        loop = Loops.getLoopFor(mbb);
        loopDepth = loop ? loop->getLoopDepth() : 0;
        isExiting = loop ? loop->isLoopExiting(mbb) : false;
      }

      // Calculate instr weight.
      bool reads, writes;
      tie(reads, writes) = mi->readsWritesVirtualRegister(li.reg);
      weight = LiveIntervals::getSpillWeight(writes, reads, loopDepth);

      // Give extra weight to what looks like a loop induction variable update.
      if (writes && isExiting && LIS.isLiveOutOfMBB(li, mbb))
        weight *= 3;

      totalWeight += weight;
    }

    // Get allocation hints from copies.
    if (noHint || !mi->isCopy())
      continue;
    unsigned hint = copyHint(mi, li.reg, tri, mri);
    if (!hint)
      continue;
    float hweight = Hint[hint] += weight;
    if (TargetRegisterInfo::isPhysicalRegister(hint)) {
      if (hweight > bestPhys && LIS.isAllocatable(hint))
        bestPhys = hweight, hintPhys = hint;
    } else {
      if (hweight > bestVirt)
        bestVirt = hweight, hintVirt = hint;
    }
  }

  Hint.clear();

  // Always prefer the physreg hint.
  if (unsigned hint = hintPhys ? hintPhys : hintVirt) {
    mri.setRegAllocationHint(li.reg, 0, hint);
    // Weakly boost the spill weight of hinted registers.
    totalWeight *= 1.01F;
  }

  // If the live interval was already unspillable, leave it that way.
  if (!Spillable)
    return;

  // Mark li as unspillable if all live ranges are tiny.
  if (li.isZeroLength(LIS.getSlotIndexes())) {
    li.markNotSpillable();
    return;
  }

  // If all of the definitions of the interval are re-materializable,
  // it is a preferred candidate for spilling. If none of the defs are
  // loads, then it's potentially very cheap to re-materialize.
  // FIXME: this gets much more complicated once we support non-trivial
  // re-materialization.
  bool isLoad = false;
  if (LIS.isReMaterializable(li, 0, isLoad)) {
    if (isLoad)
      totalWeight *= 0.9F;
    else
      totalWeight *= 0.5F;
  }

  li.weight = normalizeSpillWeight(totalWeight, li.getSize());
}

void VirtRegAuxInfo::CalculateRegClass(unsigned reg) {
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const TargetInstrInfo *TII = MF.getTarget().getInstrInfo();
  const TargetRegisterInfo *TRI = MF.getTarget().getRegisterInfo();
  const TargetRegisterClass *OldRC = MRI.getRegClass(reg);
  const TargetRegisterClass *NewRC = TRI->getLargestLegalSuperClass(OldRC);

  // Stop early if there is no room to grow.
  if (NewRC == OldRC)
    return;

  // Accumulate constraints from all uses.
  for (MachineRegisterInfo::reg_nodbg_iterator I = MRI.reg_nodbg_begin(reg),
       E = MRI.reg_nodbg_end(); I != E; ++I) {
    // TRI doesn't have accurate enough information to model this yet.
    if (I.getOperand().getSubReg())
      return;
    // Inline asm instuctions don't remember their constraints.
    if (I->isInlineAsm())
      return;
    const TargetRegisterClass *OpRC =
      TII->getRegClass(I->getDesc(), I.getOperandNo(), TRI);
    if (OpRC)
      NewRC = getCommonSubClass(NewRC, OpRC);
    if (!NewRC || NewRC == OldRC)
      return;
  }
  DEBUG(dbgs() << "Inflating " << OldRC->getName() << ':' << PrintReg(reg)
               << " to " << NewRC->getName() <<".\n");
  MRI.setRegClass(reg, NewRC);
}
<|endoftext|>


<commit_before><commit_msg>introduce extra tools<commit_after><|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file generator_expr.hpp
 * \brief Contains generator expressions.
 *
 * A generator expression is an expression that yields any number of values, for instance random values. The indexes
 * are not taken into account, but rather the sequence in which the functions are called. This is mostly useful for
 * initializing matrices / vectors.
*/

#pragma once

#include <iosfwd> //For stream support

namespace etl {

template <typename Generator>
class generator_expr final {
private:
    mutable Generator generator;

public:
    using value_type = typename Generator::value_type;

    template <typename... Args>
    explicit generator_expr(Args... args)
            : generator(std::forward<Args>(args)...) {}

    generator_expr(const generator_expr& e) = default;
    generator_expr(generator_expr&& e) noexcept = default;

    //Expression are invariant
    generator_expr& operator=(const generator_expr& e) = delete;
    generator_expr& operator=(generator_expr&& e) = delete;

    //Apply the expression

    /*!
     * \brief Returns the element at the given index
     * \param i The index
     * \return a reference to the element at the given index.
     */
    value_type operator[](std::size_t i) const {
        cpp_unused(i);
        return generator();
    }

    /*!
     * \brief Returns the value at the given index
     * This function never alters the state of the container.
     * \param i The index
     * \return the value at the given index.
     */
    value_type read_flat(std::size_t i) const {
        cpp_unused(i);
        return generator();
    }

    /*!
     * \brief Test if this expression aliases with the given expression
     * \param rhs The other expression to test
     * \return true if the two expressions aliases, false otherwise
     */
    template<typename E>
    constexpr bool alias(const E& /*rhs*/) const noexcept {
        return false;
    }

    /*!
     * \brief Apply the functor
     * \return The new value of the generator
     */
    value_type operator()() const {
        return generator();
    }

    /*!
     * \brief Returns a reference to the generator op
     * \return a reference to the generator op.
     */
    const Generator& get_generator() const {
        return generator;
    }
};

/*!
 * \brief Specialization generator_expr
 */
template <typename Generator>
struct etl_traits<etl::generator_expr<Generator>> {
    static constexpr const bool is_etl                  = true;
    static constexpr const bool is_transformer          = false;
    static constexpr const bool is_view                 = false;
    static constexpr const bool is_magic_view           = false;
    static constexpr const bool is_fast                 = true;
    static constexpr const bool is_linear               = true;
    static constexpr const bool is_value                = false;
    static constexpr const bool is_generator            = true;
    static constexpr const bool vectorizable            = false;
    static constexpr const bool needs_temporary_visitor = false;
    static constexpr const bool needs_evaluator_visitor = false;
    static constexpr const order storage_order          = order::RowMajor;
};

template <typename Generator>
std::ostream& operator<<(std::ostream& os, const generator_expr<Generator>& expr) {
    return os << expr.get_generator();
}

} //end of namespace etl
<commit_msg>Complete the doc<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file generator_expr.hpp
 * \brief Contains generator expressions.
 *
 * A generator expression is an expression that yields any number of values, for instance random values. The indexes
 * are not taken into account, but rather the sequence in which the functions are called. This is mostly useful for
 * initializing matrices / vectors.
*/

#pragma once

#include <iosfwd> //For stream support

namespace etl {

template <typename Generator>
class generator_expr final {
private:
    mutable Generator generator;

public:
    using value_type = typename Generator::value_type;

    template <typename... Args>
    explicit generator_expr(Args... args)
            : generator(std::forward<Args>(args)...) {}

    generator_expr(const generator_expr& e) = default;
    generator_expr(generator_expr&& e) noexcept = default;

    //Expression are invariant
    generator_expr& operator=(const generator_expr& e) = delete;
    generator_expr& operator=(generator_expr&& e) = delete;

    //Apply the expression

    /*!
     * \brief Returns the element at the given index
     * \param i The index
     * \return a reference to the element at the given index.
     */
    value_type operator[](std::size_t i) const {
        cpp_unused(i);
        return generator();
    }

    /*!
     * \brief Returns the value at the given index
     * This function never alters the state of the container.
     * \param i The index
     * \return the value at the given index.
     */
    value_type read_flat(std::size_t i) const {
        cpp_unused(i);
        return generator();
    }

    /*!
     * \brief Test if this expression aliases with the given expression
     * \param rhs The other expression to test
     * \return true if the two expressions aliases, false otherwise
     */
    template<typename E>
    constexpr bool alias(const E& /*rhs*/) const noexcept {
        return false;
    }

    /*!
     * \brief Apply the functor
     * \return The new value of the generator
     */
    value_type operator()() const {
        return generator();
    }

    /*!
     * \brief Returns a reference to the generator op
     * \return a reference to the generator op.
     */
    const Generator& get_generator() const {
        return generator;
    }
};

/*!
 * \brief Specialization generator_expr
 */
template <typename Generator>
struct etl_traits<etl::generator_expr<Generator>> {
    static constexpr const bool is_etl                  = true;  ///< Indicates if the type is an ETL expression
    static constexpr const bool is_transformer          = false;  ///< Indicates if the type is a transformer
    static constexpr const bool is_view                 = false; ///< Indicates if the type is a view
    static constexpr const bool is_magic_view           = false; ///< Indicates if the type is a magic view
    static constexpr const bool is_linear               = true; ///< Indicates if the expression is linear
    static constexpr const bool is_fast                 = true; ///< Indicates if the expression is fast
    static constexpr const bool is_value                = false; ///< Indicates if the expression is of value type
    static constexpr const bool is_generator            = true; ///< Indicates if the expression is a generator
    static constexpr const bool vectorizable            = false; ///< Indicates if the expression is vectorizale
    static constexpr const bool needs_temporary_visitor = false; ///< Indicates if the expression needs a temporary visitor
    static constexpr const bool needs_evaluator_visitor = false; ///< Indicates if the exxpression needs a evaluator visitor
    static constexpr const order storage_order          = order::RowMajor;           ///< The expression's storage order
};

template <typename Generator>
std::ostream& operator<<(std::ostream& os, const generator_expr<Generator>& expr) {
    return os << expr.get_generator();
}

} //end of namespace etl
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 2007-2009, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

///////////////////////////////////////////////////////////////////
//                                                               //
// Implementation of the class for SDD preprocessing             //
// Origin: E.Crescio, Torino, crescio@to.infn.it                 //
//         F.Prino, Torino, prino@to.infn.it                     //
//                                                               //
///////////////////////////////////////////////////////////////////

#include "AliITSPreprocessorSDD.h"
#include "AliITSCalibrationSDD.h"
#include "AliITSDriftSpeedSDD.h"
#include "AliITSDriftSpeedArraySDD.h"
#include "AliITSDCSAnalyzerSDD.h"
#include "AliShuttleInterface.h"
#include "AliCDBEntry.h"
#include "AliCDBMetaData.h"
#include "TObjArray.h"
#include "AliLog.h"
#include <TObjString.h>
#include <TSystem.h>
#include <TList.h>

const TString AliITSPreprocessorSDD::fgkNameHistoPedestals = "hpedestal";
const TString AliITSPreprocessorSDD::fgkNameHistoNoise = "hnoise";
ClassImp(AliITSPreprocessorSDD)

//______________________________________________________________________
AliITSPreprocessorSDD::AliITSPreprocessorSDD( AliShuttleInterface* shuttle):
    AliPreprocessor("SDD", shuttle)
{
  // constructor
  AddRunType("PULSER");
  AddRunType("INJECTOR");
  AddRunType("PHYSICS");
}

//______________________________________________________________________
UInt_t AliITSPreprocessorSDD::Process(TMap* dcsAliasMap){

  // Get DDL map from OCDB
  AliCDBEntry* entry = GetFromOCDB("Calib", "DDLMapSDD");
  if(!entry){
    Log("DDL map file not found in OCDB.");
    return 2;
  }
  AliITSDDLModuleMapSDD* ddlmap = (AliITSDDLModuleMapSDD*)entry->GetObject();
  if(!ddlmap){
    Log("AliITSDDLModuleMapSDD object not in file.");
    return 2;
  }
  ddlmap->PrintDDLMap();

  //preprocessing
  TString runType = GetRunType();
  Int_t retcode=0;

  if (runType == "PULSER"){
    Log("Process FXS files from PULSER RUN");
    retcode=ProcessPulser(ddlmap);
  }else if(runType== "INJECTOR"){
    Log("Process FXS files from INJECTOR RUN");
    retcode=ProcessInjector(ddlmap);
  }
  if(retcode!=0) return retcode;

  Log("Process DCS data");
  Bool_t retcodedcs =ProcessDCSDataPoints(dcsAliasMap);
  if(retcodedcs) return 0;
  else return 1;

}
//______________________________________________________________________
UInt_t AliITSPreprocessorSDD::ProcessPulser(AliITSDDLModuleMapSDD* ddlmap){
  // Process FXS files from PULSER run (baseline, noise, gain)
  // returns 0 in case of success,
  //         1 in case of storage error,
  //         2 in case of error with input files
  TObjArray calSDD(kNumberOfSDD);
  calSDD.SetOwner(kFALSE);
  Char_t command[100];
  Char_t inpFileName[100];
  Float_t baseline,rawnoise,cmn,corn,gain;
  Int_t isgoodan,i,im,is,isgoodmod,basmin,basoff;
  Int_t th,tl;
  Int_t numOfBadChannels[kNumberOfSDD];

  TList* sourceList = GetFileSources(kDAQ, "SDD_Calib");
  if (!sourceList){
    Log("Error: no sources found for SDD_Calib");
    return 2;
  }

  Int_t ind = 0;
  while (sourceList->At(ind)!=NULL) {
    TObjString* tarId = (TObjString*) sourceList->At(ind);
    TString tarName = GetFile(kDAQ, "SDD_Calib", tarId->GetString().Data());
    if(tarName.Length()==0){
      Log(Form("Baseline tar file from source %d not found.",ind));
      return 2;
    }
    sprintf(command,"tar -xf %s",tarName.Data());
    gSystem->Exec(command);
    ind++;
  }
  delete sourceList;

  for(Int_t iddl=0;iddl<kNumberOfDDL;iddl++){
    for(Int_t imod=0;imod<kModulesPerDDL;imod++){
      Int_t modID=ddlmap->GetModuleNumber(iddl,imod);
      if(modID==-1) continue;
      modID-=240; // to have SDD modules numbering from 0 to 260
      AliITSCalibrationSDD *cal = new AliITSCalibrationSDD("simulated");
      cal->SetUseCorrectionMaps(0,0); // temporary disabling of maps
      numOfBadChannels[modID]=0;
      Int_t badch[kNumberOfChannels];
      for(Int_t isid=0;isid<=1;isid++){
	sprintf(inpFileName,"./SDDbase_ddl%02dc%02d_sid%d.data",iddl,imod,isid);
	FILE* basFil = fopen(inpFileName,"read");
	if (basFil == 0) {
	  Log(Form("File %s not found.",inpFileName));
	  cal->SetBad();
	  continue;
	}
	fscanf(basFil,"%d %d %d\n",&im,&is,&isgoodmod);
	if(!isgoodmod) cal->SetBad();
	fscanf(basFil,"%d\n",&th);
	fscanf(basFil,"%d\n",&tl);
	cal->SetZSLowThreshold(isid,tl);
	cal->SetZSHighThreshold(isid,th);
	for(Int_t ian=0;ian<(kNumberOfChannels/2);ian++){
	  fscanf(basFil,"%d %d %f %d %d %f %f %f %f\n",&i,&isgoodan,&baseline,&basmin,&basoff,&rawnoise,&cmn,&corn,&gain);
	  Int_t ich=ian;
	  if(isid==1) ich+=256;
	  if(!isgoodan){
	    Int_t ibad=numOfBadChannels[modID];
	    badch[ibad]=ich;
	    numOfBadChannels[modID]++;
	  }
	  cal->SetBaseline(ich,baseline-basoff);
	  cal->SetNoiseAfterElectronics(ich,rawnoise);
	  cal->SetGain(ich,gain);
	}
	cal->SetDeadChannels(numOfBadChannels[modID]);
	for(Int_t ibad=0;ibad<numOfBadChannels[modID];ibad++){
	  cal->SetBadChannel(ibad,badch[ibad]);
	}
	fclose(basFil);
      }
      Log(Form("Put calib obj for module %d (DDL %d  Carlos %d)",modID,iddl,imod));
      calSDD.AddAt(cal,modID);
    }
  }
  AliCDBMetaData *md= new AliCDBMetaData();
  md->SetResponsible("Francesco Prino");
  md->SetBeamPeriod(0);
  md->SetComment("AliITSCalibrationSDD from PEDESTAL+PULSER runs");
  Bool_t retCode = Store("Calib","CalibSDD",&calSDD,md, 0, kTRUE);
  if(retCode) return 0;
  else return 1;
}
//______________________________________________________________________
UInt_t AliITSPreprocessorSDD::ProcessInjector(AliITSDDLModuleMapSDD* ddlmap){
  // Process FXS files from injector events (INJECTOR or PHYSICS runs)
  // returns 0 in case of success,
  //         1 in case of storage error,
  //         2 in case of error with input files
  TObjArray vdrift(2*kNumberOfSDD);
  vdrift.SetOwner(kFALSE);
  Char_t command[100];
  Char_t inpFileName[100];
  Int_t evNumb,polDeg;
  UInt_t timeStamp;
  Bool_t modSet[2*kNumberOfSDD]; // flag modules with good inj.
  for(Int_t ihyb=0; ihyb<2*kNumberOfSDD; ihyb++) modSet[ihyb]=0;
  Double_t nPt = 0;

  Double_t param[4];    // parameters of poly fit
  Double_t minValP0=4.; // min value for param[0]
  Double_t maxValP0=9.; // max value for param[0]
  Double_t minValP1=0.; // min value for param[1]
  Double_t aveCoef[4]={0.,0.,0.,0.};  // average param for good mod.
  Double_t defCoef[4]={6.53227,0.00128941,-5.14493e-06,0};  // default values for param
  Float_t auxP;

  TList* sourceList = GetFileSources(kDAQ, "SDD_Injec");
  if (!sourceList){
    Log("Error: no sources found for SDD_Injec");
    return 2;
  }
  Int_t ind = 0;
  while (sourceList->At(ind)!=NULL) {
    TObjString* tarId = (TObjString*) sourceList->At(ind);
    TString tarName = GetFile(kDAQ, "SDD_Injec", tarId->GetString().Data());
    if(tarName.Length()==0){
      Log(Form("Injector tar file from source %d not found.",ind));
      return 2;
    }
    sprintf(command,"tar -xf %s",tarName.Data());
    gSystem->Exec(command);
    ind++;
  }
  delete sourceList;

  for(Int_t iddl=0;iddl<kNumberOfDDL;iddl++){
    for(Int_t imod=0;imod<kModulesPerDDL;imod++){
      Int_t modID=ddlmap->GetModuleNumber(iddl,imod);
      if(modID==-1) continue;
      modID-=240; // to have SDD modules numbering from 0 to 260
      for(Int_t isid=0;isid<=1;isid++){
	AliITSDriftSpeedArraySDD *arr=new AliITSDriftSpeedArraySDD();
	sprintf(inpFileName,"./SDDinj_ddl%02dc%02d_sid%d.data",iddl,imod,isid);
	FILE* injFil = fopen(inpFileName,"read");
	if (injFil == 0) {
	  Log(Form("File %s not found.",inpFileName));
	  AliITSDriftSpeedSDD *dsp=new AliITSDriftSpeedSDD();
	  arr->AddDriftSpeed(dsp);
	  vdrift.AddAt(arr,2*modID+isid);
	  continue;
	}
	fscanf(injFil,"%d",&polDeg);
	while (!feof(injFil)){
	  fscanf(injFil,"%d %d ",&evNumb,&timeStamp);
	  if(feof(injFil)) break;
	  for(Int_t ic=0;ic<4;ic++){
	    fscanf(injFil,"%f ",&auxP);
	    param[ic]=auxP;
	  }

	  if(param[0]>minValP0 && param[0]<maxValP0 && param[1]>minValP1){
	    for(Int_t ic=0;ic<4;ic++) aveCoef[ic]+=param[ic];
	    nPt++;
	    AliITSDriftSpeedSDD *dsp=new AliITSDriftSpeedSDD(evNumb,timeStamp,polDeg,param);
	    arr->AddDriftSpeed(dsp);
	    modSet[2*modID+isid]=1;
	  }
	}
	Log(Form("Put calib obj for hybrid %d (DDL %d  Carlos %d)",2*modID+isid,iddl,imod));
	if(modSet[2*modID+isid]) vdrift.AddAt(arr,2*modID+isid);
      }
    }
  }

  // set drift speed for modules with bad injectors
  for(Int_t ic=0;ic<4;ic++){
    if(nPt>0) aveCoef[ic]/=nPt; // mean parameters
    else aveCoef[ic]=defCoef[ic]; // default parameters
  }
  AliITSDriftSpeedSDD *avdsp=new AliITSDriftSpeedSDD(evNumb,timeStamp,polDeg,aveCoef);

  for(Int_t ihyb=0; ihyb<2*kNumberOfSDD; ihyb++){
    if(modSet[ihyb]==0){
      AliWarning(Form("No good injector events for mod. %d --> use average values",ihyb/2));
      AliITSDriftSpeedArraySDD *arr=new AliITSDriftSpeedArraySDD();
      arr->AddDriftSpeed(avdsp);
      vdrift.AddAt(arr,ihyb);
    }
  }

  AliCDBMetaData *md= new AliCDBMetaData();
  md->SetResponsible("Francesco Prino");
  md->SetBeamPeriod(0);
  md->SetComment("AliITSDriftSpeedSDD from injector events");
  Bool_t retCode = Store("Calib","DriftSpeedSDD",&vdrift,md,0, kTRUE);
  if(retCode) return 0;
  else return 1;
}
//______________________________________________________________________
Bool_t AliITSPreprocessorSDD::ProcessDCSDataPoints(TMap* dcsAliasMap){
  // Process DCS data
  AliITSDCSAnalyzerSDD *dcs=new AliITSDCSAnalyzerSDD();
  dcs->AnalyzeData(dcsAliasMap);
  TObjArray refDCS(kNumberOfSDD);
  refDCS.SetOwner(kFALSE);
  for(Int_t imod=0;imod<kNumberOfSDD;imod++){
    AliITSDCSDataSDD *dcsdata=dcs->GetDCSData(imod);
    refDCS.Add(dcsdata);
  }
  AliCDBMetaData *md= new AliCDBMetaData();
  md->SetResponsible("Francesco Prino");
  md->SetBeamPeriod(0);
  md->SetComment("AliITSDCSDataSDD objects from DCS DB");
  Bool_t retCode = StoreReferenceData("DCS","DataSDD",&refDCS,md);
  return retCode;
}

<commit_msg>Problem with usage of Char_t[] fixed (Jan Fiete, Chiara)<commit_after>/**************************************************************************
 * Copyright(c) 2007-2009, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

///////////////////////////////////////////////////////////////////
//                                                               //
// Implementation of the class for SDD preprocessing             //
// Origin: E.Crescio, Torino, crescio@to.infn.it                 //
//         F.Prino, Torino, prino@to.infn.it                     //
//                                                               //
///////////////////////////////////////////////////////////////////

#include "AliITSPreprocessorSDD.h"
#include "AliITSCalibrationSDD.h"
#include "AliITSDriftSpeedSDD.h"
#include "AliITSDriftSpeedArraySDD.h"
#include "AliITSDCSAnalyzerSDD.h"
#include "AliShuttleInterface.h"
#include "AliCDBEntry.h"
#include "AliCDBMetaData.h"
#include "TObjArray.h"
#include "AliLog.h"
#include <TObjString.h>
#include <TSystem.h>
#include <TList.h>

const TString AliITSPreprocessorSDD::fgkNameHistoPedestals = "hpedestal";
const TString AliITSPreprocessorSDD::fgkNameHistoNoise = "hnoise";
ClassImp(AliITSPreprocessorSDD)

//______________________________________________________________________
AliITSPreprocessorSDD::AliITSPreprocessorSDD( AliShuttleInterface* shuttle):
    AliPreprocessor("SDD", shuttle)
{
  // constructor
  AddRunType("PULSER");
  AddRunType("INJECTOR");
  AddRunType("PHYSICS");
}

//______________________________________________________________________
UInt_t AliITSPreprocessorSDD::Process(TMap* dcsAliasMap){

  gSystem->Sleep(30000);

  // Get DDL map from OCDB
  AliCDBEntry* entry = GetFromOCDB("Calib", "DDLMapSDD");
  if(!entry){
    Log("DDL map file not found in OCDB.");
    return 2;
  }
  AliITSDDLModuleMapSDD* ddlmap = (AliITSDDLModuleMapSDD*)entry->GetObject();
  if(!ddlmap){
    Log("AliITSDDLModuleMapSDD object not in file.");
    return 2;
  }
  ddlmap->PrintDDLMap();

  //preprocessing
  TString runType = GetRunType();
  Int_t retcode=0;

  if (runType == "PULSER"){
    Log("Process FXS files from PULSER RUN");
    retcode=ProcessPulser(ddlmap);
  }else if(runType== "INJECTOR"){
    Log("Process FXS files from INJECTOR RUN");
    retcode=ProcessInjector(ddlmap);
  }
  if(retcode!=0) return retcode;

  Log("Process DCS data");
  Bool_t retcodedcs =ProcessDCSDataPoints(dcsAliasMap);
  if(retcodedcs) return 0;
  else return 1;

}
//______________________________________________________________________
UInt_t AliITSPreprocessorSDD::ProcessPulser(AliITSDDLModuleMapSDD* ddlmap){
  // Process FXS files from PULSER run (baseline, noise, gain)
  // returns 0 in case of success,
  //         1 in case of storage error,
  //         2 in case of error with input files
  TObjArray calSDD(kNumberOfSDD);
  calSDD.SetOwner(kFALSE);

  Float_t baseline,rawnoise,cmn,corn,gain;
  Int_t isgoodan,i,im,is,isgoodmod,basmin,basoff;
  Int_t th,tl;
  Int_t numOfBadChannels[kNumberOfSDD];

  TList* sourceList = GetFileSources(kDAQ, "SDD_Calib");
  if (!sourceList){
    Log("Error: no sources found for SDD_Calib");
    return 2;
  }

  Int_t ind = 0;
  while (sourceList->At(ind)!=NULL) {
    TObjString* tarId = (TObjString*) sourceList->At(ind);
    TString tarName = GetFile(kDAQ, "SDD_Calib", tarId->GetString().Data());
    if(tarName.Length()==0){
      Log(Form("Baseline tar file from source %d not found.",ind));
      return 2;
    }
    TString command;
    command.Form("tar -xf %s",tarName.Data());
    gSystem->Exec(command);
    ind++;
  }
  delete sourceList;

  for(Int_t iddl=0;iddl<kNumberOfDDL;iddl++){
    for(Int_t imod=0;imod<kModulesPerDDL;imod++){
      Int_t modID=ddlmap->GetModuleNumber(iddl,imod);
      if(modID==-1) continue;
      modID-=240; // to have SDD modules numbering from 0 to 260
      AliITSCalibrationSDD *cal = new AliITSCalibrationSDD("simulated");
      cal->SetUseCorrectionMaps(0,0); // temporary disabling of maps
      numOfBadChannels[modID]=0;
      Int_t badch[kNumberOfChannels];
      for(Int_t isid=0;isid<=1;isid++){
	TString inpFileName;
	inpFileName.Form("./SDDbase_ddl%02dc%02d_sid%d.data",iddl,imod,isid);

	FILE* basFil = fopen(inpFileName,"read");
	if (basFil == 0) {
	  Log(Form("File %s not found.",inpFileName.Data()));
	  cal->SetBad();
	  continue;
	}
	fscanf(basFil,"%d %d %d\n",&im,&is,&isgoodmod);
	if(!isgoodmod) cal->SetBad();
	fscanf(basFil,"%d\n",&th);
	fscanf(basFil,"%d\n",&tl);
	cal->SetZSLowThreshold(isid,tl);
	cal->SetZSHighThreshold(isid,th);
	for(Int_t ian=0;ian<(kNumberOfChannels/2);ian++){
	  fscanf(basFil,"%d %d %f %d %d %f %f %f %f\n",&i,&isgoodan,&baseline,&basmin,&basoff,&rawnoise,&cmn,&corn,&gain);
	  Int_t ich=ian;
	  if(isid==1) ich+=256;
	  if(!isgoodan){
	    Int_t ibad=numOfBadChannels[modID];
	    badch[ibad]=ich;
	    numOfBadChannels[modID]++;
	  }
	  cal->SetBaseline(ich,baseline-basoff);
	  cal->SetNoiseAfterElectronics(ich,rawnoise);
	  cal->SetGain(ich,gain);
	}
	cal->SetDeadChannels(numOfBadChannels[modID]);
	for(Int_t ibad=0;ibad<numOfBadChannels[modID];ibad++){
	  cal->SetBadChannel(ibad,badch[ibad]);
	}
	fclose(basFil);
      }
      Log(Form("Put calib obj for module %d (DDL %d  Carlos %d)",modID,iddl,imod));
      calSDD.AddAt(cal,modID);
    }
  }
  AliCDBMetaData *md= new AliCDBMetaData();
  md->SetResponsible("Francesco Prino");
  md->SetBeamPeriod(0);
  md->SetComment("AliITSCalibrationSDD from PEDESTAL+PULSER runs");
  Bool_t retCode = Store("Calib","CalibSDD",&calSDD,md, 0, kTRUE);
  if(retCode) return 0;
  else return 1;
}
//______________________________________________________________________
UInt_t AliITSPreprocessorSDD::ProcessInjector(AliITSDDLModuleMapSDD* ddlmap){
  // Process FXS files from injector events (INJECTOR or PHYSICS runs)
  // returns 0 in case of success,
  //         1 in case of storage error,
  //         2 in case of error with input files
  TObjArray vdrift(2*kNumberOfSDD);
  vdrift.SetOwner(kFALSE);
  Int_t evNumb,polDeg;
  UInt_t timeStamp;
  Bool_t modSet[2*kNumberOfSDD]; // flag modules with good inj.
  for(Int_t ihyb=0; ihyb<2*kNumberOfSDD; ihyb++) modSet[ihyb]=0;
  Double_t nPt = 0;

  Double_t param[4];    // parameters of poly fit
  Double_t minValP0=4.; // min value for param[0]
  Double_t maxValP0=9.; // max value for param[0]
  Double_t minValP1=0.; // min value for param[1]
  Double_t aveCoef[4]={0.,0.,0.,0.};  // average param for good mod.
  Double_t defCoef[4]={6.53227,0.00128941,-5.14493e-06,0};  // default values for param
  Float_t auxP;

  TList* sourceList = GetFileSources(kDAQ, "SDD_Injec");
  if (!sourceList){
    Log("Error: no sources found for SDD_Injec");
    return 2;
  }
  Int_t ind = 0;
  while (sourceList->At(ind)!=NULL) {
    TObjString* tarId = (TObjString*) sourceList->At(ind);
    TString tarName = GetFile(kDAQ, "SDD_Injec", tarId->GetString().Data());
    if(tarName.Length()==0){
      Log(Form("Injector tar file from source %d not found.",ind));
      return 2;
    }
    TString command;
    command.Form("tar -xf %s",tarName.Data());
    gSystem->Exec(command);
    ind++;
  }
  delete sourceList;

  for(Int_t iddl=0;iddl<kNumberOfDDL;iddl++){
    for(Int_t imod=0;imod<kModulesPerDDL;imod++){
      Int_t modID=ddlmap->GetModuleNumber(iddl,imod);
      if(modID==-1) continue;
      modID-=240; // to have SDD modules numbering from 0 to 260
      for(Int_t isid=0;isid<=1;isid++){
	AliITSDriftSpeedArraySDD *arr=new AliITSDriftSpeedArraySDD();
	TString inpFileName;
	inpFileName.Form("./SDDinj_ddl%02dc%02d_sid%d.data",iddl,imod,isid);
	FILE* injFil = fopen(inpFileName,"read");
	if (injFil == 0) {
	  Log(Form("File %s not found.",inpFileName.Data()));
	  AliITSDriftSpeedSDD *dsp=new AliITSDriftSpeedSDD();
	  arr->AddDriftSpeed(dsp);
	  vdrift.AddAt(arr,2*modID+isid);
	  continue;
	}
	fscanf(injFil,"%d",&polDeg);
	while (!feof(injFil)){
	  fscanf(injFil,"%d %d ",&evNumb,&timeStamp);
	  if(feof(injFil)) break;
	  for(Int_t ic=0;ic<4;ic++){
	    fscanf(injFil,"%f ",&auxP);
	    param[ic]=auxP;
	  }

	  if(param[0]>minValP0 && param[0]<maxValP0 && param[1]>minValP1){
	    for(Int_t ic=0;ic<4;ic++) aveCoef[ic]+=param[ic];
	    nPt++;
	    AliITSDriftSpeedSDD *dsp=new AliITSDriftSpeedSDD(evNumb,timeStamp,polDeg,param);
	    arr->AddDriftSpeed(dsp);
	    modSet[2*modID+isid]=1;
	  }
	}
	Log(Form("Put calib obj for hybrid %d (DDL %d  Carlos %d)",2*modID+isid,iddl,imod));
	if(modSet[2*modID+isid]) vdrift.AddAt(arr,2*modID+isid);
      }
    }
  }

  // set drift speed for modules with bad injectors
  for(Int_t ic=0;ic<4;ic++){
    if(nPt>0) aveCoef[ic]/=nPt; // mean parameters
    else aveCoef[ic]=defCoef[ic]; // default parameters
  }
  AliITSDriftSpeedSDD *avdsp=new AliITSDriftSpeedSDD(evNumb,timeStamp,polDeg,aveCoef);

  for(Int_t ihyb=0; ihyb<2*kNumberOfSDD; ihyb++){
    if(modSet[ihyb]==0){
      AliWarning(Form("No good injector events for mod. %d --> use average values",ihyb/2));
      AliITSDriftSpeedArraySDD *arr=new AliITSDriftSpeedArraySDD();
      arr->AddDriftSpeed(avdsp);
      vdrift.AddAt(arr,ihyb);
    }
  }

  AliCDBMetaData *md= new AliCDBMetaData();
  md->SetResponsible("Francesco Prino");
  md->SetBeamPeriod(0);
  md->SetComment("AliITSDriftSpeedSDD from injector events");
  Bool_t retCode = Store("Calib","DriftSpeedSDD",&vdrift,md,0, kTRUE);
  if(retCode) return 0;
  else return 1;
}
//______________________________________________________________________
Bool_t AliITSPreprocessorSDD::ProcessDCSDataPoints(TMap* dcsAliasMap){
  // Process DCS data
  AliITSDCSAnalyzerSDD *dcs=new AliITSDCSAnalyzerSDD();
  dcs->AnalyzeData(dcsAliasMap);
  TObjArray refDCS(kNumberOfSDD);
  refDCS.SetOwner(kFALSE);
  for(Int_t imod=0;imod<kNumberOfSDD;imod++){
    AliITSDCSDataSDD *dcsdata=dcs->GetDCSData(imod);
    refDCS.Add(dcsdata);
  }
  AliCDBMetaData *md= new AliCDBMetaData();
  md->SetResponsible("Francesco Prino");
  md->SetBeamPeriod(0);
  md->SetComment("AliITSDCSDataSDD objects from DCS DB");
  Bool_t retCode = StoreReferenceData("DCS","DataSDD",&refDCS,md);
  return retCode;
}

<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/QR>

template<typename MatrixType> void eigensolver(const MatrixType& m)
{
  /* this test covers the following files:
     EigenSolver.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;

  MatrixType a = MatrixType::random(rows,cols);
  MatrixType covMat =  a.adjoint() * a;

  SelfAdjointEigenSolver<MatrixType> eiSymm(covMat);
  VERIFY_IS_APPROX(covMat * eiSymm.eigenvectors(), eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal());

  EigenSolver<MatrixType> eiNotSymmButSymm(covMat);
  VERIFY_IS_APPROX((covMat.template cast<Complex>()) * (eiNotSymmButSymm.eigenvectors().template cast<Complex>()),
    (eiNotSymmButSymm.eigenvectors().template cast<Complex>()) * (eiNotSymmButSymm.eigenvalues().asDiagonal()));

  EigenSolver<MatrixType> eiNotSymm(a);
//   VERIFY_IS_APPROX(a.template cast<Complex>() * eiNotSymm.eigenvectors().template cast<Complex>(),
//     eiNotSymm.eigenvectors().template cast<Complex>() * eiNotSymm.eigenvalues().asDiagonal());

}

void test_eigensolver()
{
  for(int i = 0; i < 1; i++) {
    CALL_SUBTEST( eigensolver(Matrix3f()) );
    CALL_SUBTEST( eigensolver(Matrix4d()) );
    CALL_SUBTEST( eigensolver(MatrixXd(7,7)) );
  }
}
<commit_msg>update of the eigeinsolver unit test to check complex<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/QR>

template<typename MatrixType> void eigensolver(const MatrixType& m)
{
  /* this test covers the following files:
     EigenSolver.h, SelfAdjointEigenSolver.h (and indirectly: Tridiagonalization.h)
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;

  MatrixType a = MatrixType::random(rows,cols);
  MatrixType covMat =  a.adjoint() * a;

  SelfAdjointEigenSolver<MatrixType> eiSymm(covMat);
  VERIFY_IS_APPROX(covMat * eiSymm.eigenvectors(), (eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal().eval()));

//   EigenSolver<MatrixType> eiNotSymmButSymm(covMat);
//   VERIFY_IS_APPROX((covMat.template cast<Complex>()) * (eiNotSymmButSymm.eigenvectors().template cast<Complex>()),
//     (eiNotSymmButSymm.eigenvectors().template cast<Complex>()) * (eiNotSymmButSymm.eigenvalues().asDiagonal()));

//   EigenSolver<MatrixType> eiNotSymm(a);
//   VERIFY_IS_APPROX(a.template cast<Complex>() * eiNotSymm.eigenvectors().template cast<Complex>(),
//     eiNotSymm.eigenvectors().template cast<Complex>() * eiNotSymm.eigenvalues().asDiagonal());

}

void test_eigensolver()
{
  for(int i = 0; i < 1; i++) {
    CALL_SUBTEST( eigensolver(Matrix3f()) );
    CALL_SUBTEST( eigensolver(Matrix4d()) );
    CALL_SUBTEST( eigensolver(MatrixXd(7,7)) );
    CALL_SUBTEST( eigensolver(MatrixXcd(6,6)) );
  }
}
<|endoftext|>


<commit_before>#pragma warning (disable:4996)

#define WIN32_LEAN_AND_MEAN
#pragma comment (lib, "Shlwapi.lib")

#include <Windows.h>
#include <Shlwapi.h>
#include <unordered_map>
#include <mutex>
#include <queue>
using namespace std;

#define BUF_SIZE MAX_PATH * 3

long long CurrentTime()
{
    long long t;
    GetSystemTimeAsFileTime((LPFILETIME) &t);
    return t;
}

BOOL unhook_by_code(LPCTSTR szDllName, LPCTSTR szFuncName, PBYTE pOrgBytes)
{
    FARPROC pFunc;
    DWORD dwOldProtect;

    // API ּ Ѵ
    pFunc = GetProcAddress(GetModuleHandle(szDllName), szFuncName);

    //  ڵ (5 byte)   ޸𸮿 WRITE Ӽ ߰
    VirtualProtect((LPVOID) pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // Unhook
    memcpy(pFunc, pOrgBytes, 5);

    // ޸ Ӽ
    VirtualProtect((LPVOID) pFunc, 5, dwOldProtect, &dwOldProtect);

    return TRUE;
}

BOOL hook_by_code(LPCTSTR szDllName, LPCTSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
{
    FARPROC pfnOrg;
    DWORD dwOldProtect, dwAddress;
    BYTE pBuf[5] = { 0xE9, 0, };
    PBYTE pByte;

    // ŷ API ּҸ Ѵ
    pfnOrg = (FARPROC) GetProcAddress(GetModuleHandle(szDllName), szFuncName);
    pByte = (PBYTE) pfnOrg;

    //  ̹ ŷǾ ִٸ return FALSE
    if (pByte[0] == 0xE9)
        return FALSE;

    // 5 byte ġ Ͽ ޸𸮿 WRITE Ӽ ߰
    VirtualProtect((LPVOID) pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // ڵ (5 byte)
    memcpy(pOrgBytes, pfnOrg, 5);

    // JMP ּҰ (E9 XXXX)
    // => XXXX = pfnNew - pfnOrg - 5
    dwAddress = (DWORD) pfnNew - (DWORD) pfnOrg - 5;
    memcpy(&pBuf[1], &dwAddress, 4);

    // Hook - 5 byte ġ(JMP XXXX)
    memcpy(pfnOrg, pBuf, 5);

    // ޸ Ӽ
    VirtualProtect((LPVOID) pfnOrg, 5, dwOldProtect, &dwOldProtect);

    return TRUE;
}

mutex STLMutex;

HANDLE hPipe;
volatile bool bCancelPipeThread;
volatile bool bPipeConnected;

queue<string> MessageQueue;
HANDLE hQueuePushed;

DWORD WINAPI PipeThread(LPVOID lParam)
{
    hPipe = CreateNamedPipeA("\\\\.\\pipe\\osu!Lyrics", PIPE_ACCESS_OUTBOUND,
        PIPE_TYPE_MESSAGE | PIPE_WAIT, 1, BUF_SIZE * 5, 0, INFINITE, NULL);
    //   û   Ŭ̾Ʈ
    while (!bCancelPipeThread)
    {
        // ConnectNamedPipe Ŭ̾Ʈ    :
        // Ҵ DisconnectNamedPipe
        if (ConnectNamedPipe(hPipe, NULL) || GetLastError() == ERROR_PIPE_CONNECTED)
        {
            bPipeConnected = true;

            STLMutex.lock();
            bool empty = MessageQueue.empty();
            STLMutex.unlock();
            if (empty)
            {
                // ޼ ť   3ʰ ٷ ȣ  ٽ ٸ
                WaitForSingleObject(hQueuePushed, 3000);
                continue;
            }

            STLMutex.lock();
            string message = MessageQueue.front();
            STLMutex.unlock();
            OVERLAPPED overlapped = {};
            if (WriteFileEx(hPipe, message.c_str(), message.length(), &overlapped, [](DWORD, DWORD, LPOVERLAPPED) {}))
            {
                STLMutex.lock();
                MessageQueue.pop();
                STLMutex.unlock();
                continue;
            }
        }
        bPipeConnected = false;
        DisconnectNamedPipe(hPipe);
    }
    // Ŭ̾Ʈ
    bPipeConnected = false;
    DisconnectNamedPipe(hPipe);
    CloseHandle(hPipe);
    return 0;
}

typedef BOOL (WINAPI *tReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
tReadFile pReadFile;
mutex HookMutex;
BYTE pReadFileHook[5];

unordered_map<string, string> AudioInfo;

// osu! ReadFile ȣϸ   osu!Lyrics
BOOL WINAPI hkReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
    long long calledAt = CurrentTime();

    HookMutex.lock();
    unhook_by_code("kernel32.dll", "ReadFile", pReadFileHook);
    BOOL result = pReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
    hook_by_code("kernel32.dll", "ReadFile", (PROC) hkReadFile, pReadFileHook);
    HookMutex.unlock();
    if (!result)
    {
        return FALSE;
    }

    char path[MAX_PATH];
    DWORD pathLength = GetFinalPathNameByHandle(hFile, path, MAX_PATH, VOLUME_NAME_DOS);
    //                  1: \\?\D:\Games\osu!\...
    DWORD seekPosition = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - *lpNumberOfBytesRead;
    //  д  Ʈ ̰ պκ оٸ:
    // AudioFilename պκп  /  ڵ       !
    if (strnicmp(".osu", &path[pathLength - 4], 4) == 0 && seekPosition == 0)
    {
        // strtok ҽ ϹǷ ϴ
        char *buffer = strdup((char *) lpBuffer);
        char *line = strtok(buffer, "\n");
        while (line != NULL)
        {
            // Ʈ
            if (strnicmp(line, "AudioFilename:", 14) == 0)
            {
                char *beatmapDir = strdup(path);
                PathRemoveFileSpec(beatmapDir);

                char audioPath[MAX_PATH];

                // get value & trim
                int i = 14;
                for (; line[i] == ' '; i++);
                buffer[0] = '\0';
                strncat(buffer, &line[i], strlen(line) - i - 1);
                PathCombine(audioPath, beatmapDir, buffer);

                // ˻  ҹ ϹǷ
                WIN32_FIND_DATA fdata;
                FindClose(FindFirstFile(audioPath, &fdata));
                PathRemoveFileSpec(audioPath);
                PathCombine(audioPath, audioPath, fdata.cFileName);

                STLMutex.lock();
                AudioInfo.insert(make_pair(string(audioPath), string(path)));
                STLMutex.unlock();

                free(beatmapDir);
                break;
            }
            line = strtok(NULL, "\n");
        }
        free(buffer);
    }
    else
    {
        STLMutex.lock();
        // [ audioPath, beatmapPath ]
        unordered_map<string, string>::iterator pair = AudioInfo.find(string(path));
        bool found = pair != AudioInfo.end();
        STLMutex.unlock();
        if (found)
        {
            char message[BUF_SIZE];
            sprintf(message, "%llx|%s|%lx|%s\n", calledAt, &path[4], seekPosition, &pair->second[4]);
            STLMutex.lock();
            MessageQueue.push(string(message));
            STLMutex.unlock();
            SetEvent(hQueuePushed);
        }
    }
    return TRUE;
}

HANDLE hPipeThread;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
        hPipeThread = CreateThread(NULL, 0, PipeThread, NULL, 0, NULL);
        hQueuePushed = CreateEventA(NULL, TRUE, FALSE, NULL);

        HookMutex.lock();
        pReadFile = (tReadFile) GetProcAddress(GetModuleHandle("kernel32.dll"), "ReadFile");
        hook_by_code("kernel32.dll", "ReadFile", (PROC) hkReadFile, pReadFileHook);
        HookMutex.unlock();
    }
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
        HookMutex.lock();
        unhook_by_code("kernel32.dll", "ReadFile", pReadFileHook);
        HookMutex.unlock();

        bCancelPipeThread = true;
        DisconnectNamedPipe(hPipe);
        WaitForSingleObject(hPipeThread, INFINITE);
        CloseHandle(hQueuePushed);
        CloseHandle(hPipeThread);
    }
    return TRUE;
}<commit_msg>자원 낭비 방지<commit_after>#pragma warning (disable:4996)

#define WIN32_LEAN_AND_MEAN
#pragma comment (lib, "Shlwapi.lib")

#include <Windows.h>
#include <Shlwapi.h>
#include <unordered_map>
#include <mutex>
#include <queue>
using namespace std;

#define BUF_SIZE MAX_PATH * 3

long long CurrentTime()
{
    long long t;
    GetSystemTimeAsFileTime((LPFILETIME) &t);
    return t;
}

BOOL unhook_by_code(LPCTSTR szDllName, LPCTSTR szFuncName, PBYTE pOrgBytes)
{
    FARPROC pFunc;
    DWORD dwOldProtect;

    // API ּ Ѵ
    pFunc = GetProcAddress(GetModuleHandle(szDllName), szFuncName);

    //  ڵ (5 byte)   ޸𸮿 WRITE Ӽ ߰
    VirtualProtect((LPVOID) pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // Unhook
    memcpy(pFunc, pOrgBytes, 5);

    // ޸ Ӽ
    VirtualProtect((LPVOID) pFunc, 5, dwOldProtect, &dwOldProtect);

    return TRUE;
}

BOOL hook_by_code(LPCTSTR szDllName, LPCTSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
{
    FARPROC pfnOrg;
    DWORD dwOldProtect, dwAddress;
    BYTE pBuf[5] = { 0xE9, 0, };
    PBYTE pByte;

    // ŷ API ּҸ Ѵ
    pfnOrg = (FARPROC) GetProcAddress(GetModuleHandle(szDllName), szFuncName);
    pByte = (PBYTE) pfnOrg;

    //  ̹ ŷǾ ִٸ return FALSE
    if (pByte[0] == 0xE9)
        return FALSE;

    // 5 byte ġ Ͽ ޸𸮿 WRITE Ӽ ߰
    VirtualProtect((LPVOID) pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // ڵ (5 byte)
    memcpy(pOrgBytes, pfnOrg, 5);

    // JMP ּҰ (E9 XXXX)
    // => XXXX = pfnNew - pfnOrg - 5
    dwAddress = (DWORD) pfnNew - (DWORD) pfnOrg - 5;
    memcpy(&pBuf[1], &dwAddress, 4);

    // Hook - 5 byte ġ(JMP XXXX)
    memcpy(pfnOrg, pBuf, 5);

    // ޸ Ӽ
    VirtualProtect((LPVOID) pfnOrg, 5, dwOldProtect, &dwOldProtect);

    return TRUE;
}

mutex STLMutex;

HANDLE hPipe;
volatile bool bCancelPipeThread;
volatile bool bPipeConnected;

queue<string> MessageQueue;
HANDLE hQueuePushed;

DWORD WINAPI PipeThread(LPVOID lParam)
{
    hPipe = CreateNamedPipeA("\\\\.\\pipe\\osu!Lyrics", PIPE_ACCESS_OUTBOUND,
        PIPE_TYPE_MESSAGE | PIPE_WAIT, 1, BUF_SIZE * 5, 0, INFINITE, NULL);
    //   û   Ŭ̾Ʈ
    while (!bCancelPipeThread)
    {
        // ConnectNamedPipe Ŭ̾Ʈ    :
        // Ҵ DisconnectNamedPipe
        if (ConnectNamedPipe(hPipe, NULL) || GetLastError() == ERROR_PIPE_CONNECTED)
        {
            bPipeConnected = true;

            STLMutex.lock();
            bool empty = MessageQueue.empty();
            STLMutex.unlock();
            if (empty)
            {
                // ޼ ť   3ʰ ٷ ȣ  ٽ ٸ
                WaitForSingleObject(hQueuePushed, 3000);
                continue;
            }

            STLMutex.lock();
            string message = MessageQueue.front();
            STLMutex.unlock();
            OVERLAPPED overlapped = {};
            if (WriteFileEx(hPipe, message.c_str(), message.length(), &overlapped, [](DWORD, DWORD, LPOVERLAPPED) {}))
            {
                STLMutex.lock();
                MessageQueue.pop();
                STLMutex.unlock();
                continue;
            }
        }
        bPipeConnected = false;
        DisconnectNamedPipe(hPipe);
    }
    // Ŭ̾Ʈ
    bPipeConnected = false;
    DisconnectNamedPipe(hPipe);
    CloseHandle(hPipe);
    return 0;
}

typedef BOOL (WINAPI *tReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
tReadFile pReadFile;
mutex HookMutex;
BYTE pReadFileHook[5];

unordered_map<string, string> AudioInfo;

// osu! ReadFile ȣϸ   osu!Lyrics
BOOL WINAPI hkReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
    long long calledAt = CurrentTime();

    HookMutex.lock();
    unhook_by_code("kernel32.dll", "ReadFile", pReadFileHook);
    BOOL result = pReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
    hook_by_code("kernel32.dll", "ReadFile", (PROC) hkReadFile, pReadFileHook);
    HookMutex.unlock();
    if (!result)
    {
        return FALSE;
    }

    char path[MAX_PATH];
    DWORD pathLength = GetFinalPathNameByHandle(hFile, path, MAX_PATH, VOLUME_NAME_DOS);
    //                  1: \\?\D:\Games\osu!\...
    DWORD seekPosition = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - *lpNumberOfBytesRead;
    //  д  Ʈ ̰ պκ оٸ:
    // AudioFilename պκп  /  ڵ       !
    if (strnicmp(".osu", &path[pathLength - 4], 4) == 0 && seekPosition == 0)
    {
        // strtok ҽ ϹǷ ϴ
        char *buffer = strdup((char *) lpBuffer);
        char *line = strtok(buffer, "\n");
        while (line != NULL)
        {
            // Ʈ
            if (strnicmp(line, "AudioFilename:", 14) == 0)
            {
                char *beatmapDir = strdup(path);
                PathRemoveFileSpec(beatmapDir);

                char audioPath[MAX_PATH];

                // get value & trim
                int i = 14;
                for (; line[i] == ' '; i++);
                buffer[0] = '\0';
                strncat(buffer, &line[i], strlen(line) - i - 1);
                PathCombine(audioPath, beatmapDir, buffer);

                // ˻  ҹ ϹǷ
                WIN32_FIND_DATA fdata;
                FindClose(FindFirstFile(audioPath, &fdata));
                PathRemoveFileSpec(audioPath);
                PathCombine(audioPath, audioPath, fdata.cFileName);

                STLMutex.lock();
                AudioInfo.insert(make_pair(string(audioPath), string(path)));
                STLMutex.unlock();

                free(beatmapDir);
                break;
            }
            line = strtok(NULL, "\n");
        }
        free(buffer);
    }
    //     縦   ʴٴ :
    // osu!  ÷̿ ϰ ... ڿ
    else if (bPipeConnected)
    {
        STLMutex.lock();
        // [ audioPath, beatmapPath ]
        unordered_map<string, string>::iterator pair = AudioInfo.find(string(path));
        bool found = pair != AudioInfo.end();
        STLMutex.unlock();
        if (found)
        {
            char message[BUF_SIZE];
            sprintf(message, "%llx|%s|%lx|%s\n", calledAt, &path[4], seekPosition, &pair->second[4]);
            STLMutex.lock();
            MessageQueue.push(string(message));
            STLMutex.unlock();
            SetEvent(hQueuePushed);
        }
    }
    return TRUE;
}

HANDLE hPipeThread;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
        hPipeThread = CreateThread(NULL, 0, PipeThread, NULL, 0, NULL);
        hQueuePushed = CreateEventA(NULL, TRUE, FALSE, NULL);

        HookMutex.lock();
        pReadFile = (tReadFile) GetProcAddress(GetModuleHandle("kernel32.dll"), "ReadFile");
        hook_by_code("kernel32.dll", "ReadFile", (PROC) hkReadFile, pReadFileHook);
        HookMutex.unlock();
    }
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
        HookMutex.lock();
        unhook_by_code("kernel32.dll", "ReadFile", pReadFileHook);
        HookMutex.unlock();

        bCancelPipeThread = true;
        DisconnectNamedPipe(hPipe);
        WaitForSingleObject(hPipeThread, INFINITE);
        CloseHandle(hQueuePushed);
        CloseHandle(hPipeThread);
    }
    return TRUE;
}<|endoftext|>