<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "ClientMonitor.h"
#include "Monitor.h"
#include "MDSMonitor.h"
#include "OSDMonitor.h"
#include "MonitorStore.h"

#include "messages/MMonMap.h"
#include "messages/MClientMount.h"
#include "messages/MClientUnmount.h"

#include "common/Timer.h"

#include "config.h"

#define  dout(l) if (l<=g_conf.debug || l<=g_conf.debug_mon) *_dout << dbeginl << g_clock.now() << " mon" << mon->whoami << (mon->is_starting() ? (const char*)"(starting)":(mon->is_leader() ? (const char*)"(leader)":(mon->is_peon() ? (const char*)"(peon)":(const char*)"(?\?)"))) << ".client v" << client_map.version << " "
#define  derr(l) if (l<=g_conf.debug || l<=g_conf.debug_mon) *_derr << dbeginl << g_clock.now() << " mon" << mon->whoami << (mon->is_starting() ? (const char*)"(starting)":(mon->is_leader() ? (const char*)"(leader)":(mon->is_peon() ? (const char*)"(peon)":(const char*)"(?\?)"))) << ".client v" << client_map.version << " "

bool ClientMonitor::update_from_paxos()
{
  assert(paxos->is_active());

  version_t paxosv = paxos->get_version();
  if (paxosv == client_map.version) return true;
  assert(paxosv >= client_map.version);

  dout(10) << "update_from_paxos paxosv " << paxosv
	   << ", my v " << client_map.version << dendl;

  if (client_map.version == 0 && paxosv > 1 &&
      mon->store->exists_bl_ss("clientmap","latest")) {
    // starting up: load latest
    dout(7) << "update_from_paxos startup: loading latest full clientmap" << dendl;
    bufferlist bl;
    mon->store->get_bl_ss(bl, "clientmap", "latest");
    int off = 0;
    client_map._decode(bl, off);
  }

  // walk through incrementals
  while (paxosv > client_map.version) {
    bufferlist bl;
    bool success = paxos->read(client_map.version+1, bl);
    if (success) {
      dout(7) << "update_from_paxos  applying incremental " << client_map.version+1 << dendl;
      Incremental inc;
      int off = 0;
      inc._decode(bl, off);
      client_map.apply_incremental(inc);

      dout(1) << client_map.client_addr.size() << " clients (+"
	      << inc.mount.size() << " -" << inc.unmount.size() << ")"
	      << dendl;

    } else {
      dout(7) << "update_from_paxos  couldn't read incremental " << client_map.version+1 << dendl;
      return false;
    }
  }

  // save latest
  bufferlist bl;
  client_map._encode(bl);
  mon->store->put_bl_ss(bl, "clientmap", "latest");

  return true;
}

void ClientMonitor::create_pending()
{
  pending_inc = Incremental();
  pending_inc.version = client_map.version + 1;
  pending_inc.next_client = client_map.next_client;
  dout(10) << "create_pending v " << pending_inc.version
	   << ", next is " << pending_inc.next_client
	   << dendl;
}

void ClientMonitor::create_initial()
{
  dout(10) << "create_initial -- creating initial map" << dendl;
}

void ClientMonitor::committed()
{

}

void ClientMonitor::encode_pending(bufferlist &bl)
{
  dout(10) << "encode_pending v " << pending_inc.version
	   << ", next is " << pending_inc.next_client
	   << dendl;
  assert(paxos->get_version() + 1 == pending_inc.version);
  pending_inc._encode(bl);
}

// -------

bool ClientMonitor::preprocess_query(Message *m)
{
  dout(10) << "preprocess_query " << *m << " from " << m->get_source_inst() << dendl;

  switch (m->get_type()) {
  case CEPH_MSG_CLIENT_MOUNT:
    {
      // already mounted?
      entity_addr_t addr = m->get_source_addr();
      if (client_map.addr_client.count(addr)) {
	int client = client_map.addr_client[addr];
	dout(7) << " client" << client << " already mounted" << dendl;
	_mounted(client, (MClientMount*)m);
	return true;
      }
    }
    return false;

  case CEPH_MSG_CLIENT_UNMOUNT:
    {
      // already unmounted?
      int client = m->get_source().num();
      if (client_map.client_addr.count(client) == 0) {
	dout(7) << " client" << client << " not mounted" << dendl;
	_unmounted((MClientUnmount*)m);
	return true;
      }
    }
    return false;

  default:
    assert(0);
    delete m;
    return true;
  }
}

bool ClientMonitor::prepare_update(Message *m)
{
  dout(10) << "prepare_update " << *m << " from " << m->get_source_inst() << dendl;

  switch (m->get_type()) {
  case CEPH_MSG_CLIENT_MOUNT:
    {
      entity_addr_t addr = m->get_source_addr();
      int client = -1;
      if (m->get_source().is_client())
	client = m->get_source().num();

      // choose a client id
      if (client < 0) {
	client = pending_inc.next_client;
	dout(10) << "mount: assigned client" << client << " to " << addr << dendl;
      } else {
	dout(10) << "mount: client" << client << " requested by " << addr << dendl;
	if (client_map.client_addr.count(client)) {
	  assert(client_map.client_addr[client] != addr);
	  dout(0) << "mount: WARNING: client" << client << " requested by " << addr
		  << ", which used to be "  << client_map.client_addr[client] << dendl;
	}
      }

      pending_inc.add_mount(client, addr);
      paxos->wait_for_commit(new C_Mounted(this, client, (MClientMount*)m));
    }
    return true;

  case CEPH_MSG_CLIENT_UNMOUNT:
    {
      assert(m->get_source().is_client());
      int client = m->get_source().num();

      assert(client_map.client_addr.count(client));

      pending_inc.add_unmount(client);
      paxos->wait_for_commit(new C_Unmounted(this, (MClientUnmount*)m));
    }
    return true;

  default:
    assert(0);
    delete m;
    return false;
  }

}

// MOUNT

void ClientMonitor::_mounted(int client, MClientMount *m)
{
  entity_inst_t to;
  to.addr = m->get_source_addr();
  to.name = entity_name_t::CLIENT(client);

  dout(10) << "_mounted client" << client << " at " << to << dendl;

  // reply with latest mds, osd maps
  mon->mdsmon->send_latest(to);
  mon->osdmon->send_latest(to);

  dout(10) << "sending monmap to " << to << dendl;
  bufferlist bl;
  mon->monmap->encode(bl);
  mon->messenger->send_message(new MMonMap(bl), to);

  delete m;
}

void ClientMonitor::_unmounted(MClientUnmount *m)
{
  dout(10) << "_unmounted " << m->get_source_inst() << dendl;

  // reply with (same) unmount message
  mon->messenger->send_message(m, m->get_source_inst());

  // auto-shutdown?
  // (hack for fakesyn/newsyn, mostly)
  if (mon->is_leader() &&
      client_map.version > 1 &&
      client_map.client_addr.empty() &&
      g_conf.mon_stop_on_last_unmount &&
      !mon->is_stopping()) {
    dout(1) << "last client unmounted" << dendl;
    mon->do_stop();
  }
}

<commit_msg>mon: send new clients monmap before osd, mds maps<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "ClientMonitor.h"
#include "Monitor.h"
#include "MDSMonitor.h"
#include "OSDMonitor.h"
#include "MonitorStore.h"

#include "messages/MMonMap.h"
#include "messages/MClientMount.h"
#include "messages/MClientUnmount.h"

#include "common/Timer.h"

#include "config.h"

#define  dout(l) if (l<=g_conf.debug || l<=g_conf.debug_mon) *_dout << dbeginl << g_clock.now() << " mon" << mon->whoami << (mon->is_starting() ? (const char*)"(starting)":(mon->is_leader() ? (const char*)"(leader)":(mon->is_peon() ? (const char*)"(peon)":(const char*)"(?\?)"))) << ".client v" << client_map.version << " "
#define  derr(l) if (l<=g_conf.debug || l<=g_conf.debug_mon) *_derr << dbeginl << g_clock.now() << " mon" << mon->whoami << (mon->is_starting() ? (const char*)"(starting)":(mon->is_leader() ? (const char*)"(leader)":(mon->is_peon() ? (const char*)"(peon)":(const char*)"(?\?)"))) << ".client v" << client_map.version << " "

bool ClientMonitor::update_from_paxos()
{
  assert(paxos->is_active());

  version_t paxosv = paxos->get_version();
  if (paxosv == client_map.version) return true;
  assert(paxosv >= client_map.version);

  dout(10) << "update_from_paxos paxosv " << paxosv
	   << ", my v " << client_map.version << dendl;

  if (client_map.version == 0 && paxosv > 1 &&
      mon->store->exists_bl_ss("clientmap","latest")) {
    // starting up: load latest
    dout(7) << "update_from_paxos startup: loading latest full clientmap" << dendl;
    bufferlist bl;
    mon->store->get_bl_ss(bl, "clientmap", "latest");
    int off = 0;
    client_map._decode(bl, off);
  }

  // walk through incrementals
  while (paxosv > client_map.version) {
    bufferlist bl;
    bool success = paxos->read(client_map.version+1, bl);
    if (success) {
      dout(7) << "update_from_paxos  applying incremental " << client_map.version+1 << dendl;
      Incremental inc;
      int off = 0;
      inc._decode(bl, off);
      client_map.apply_incremental(inc);

      dout(1) << client_map.client_addr.size() << " clients (+"
	      << inc.mount.size() << " -" << inc.unmount.size() << ")"
	      << dendl;

    } else {
      dout(7) << "update_from_paxos  couldn't read incremental " << client_map.version+1 << dendl;
      return false;
    }
  }

  // save latest
  bufferlist bl;
  client_map._encode(bl);
  mon->store->put_bl_ss(bl, "clientmap", "latest");

  return true;
}

void ClientMonitor::create_pending()
{
  pending_inc = Incremental();
  pending_inc.version = client_map.version + 1;
  pending_inc.next_client = client_map.next_client;
  dout(10) << "create_pending v " << pending_inc.version
	   << ", next is " << pending_inc.next_client
	   << dendl;
}

void ClientMonitor::create_initial()
{
  dout(10) << "create_initial -- creating initial map" << dendl;
}

void ClientMonitor::committed()
{

}

void ClientMonitor::encode_pending(bufferlist &bl)
{
  dout(10) << "encode_pending v " << pending_inc.version
	   << ", next is " << pending_inc.next_client
	   << dendl;
  assert(paxos->get_version() + 1 == pending_inc.version);
  pending_inc._encode(bl);
}

// -------

bool ClientMonitor::preprocess_query(Message *m)
{
  dout(10) << "preprocess_query " << *m << " from " << m->get_source_inst() << dendl;

  switch (m->get_type()) {
  case CEPH_MSG_CLIENT_MOUNT:
    {
      // already mounted?
      entity_addr_t addr = m->get_source_addr();
      if (client_map.addr_client.count(addr)) {
	int client = client_map.addr_client[addr];
	dout(7) << " client" << client << " already mounted" << dendl;
	_mounted(client, (MClientMount*)m);
	return true;
      }
    }
    return false;

  case CEPH_MSG_CLIENT_UNMOUNT:
    {
      // already unmounted?
      int client = m->get_source().num();
      if (client_map.client_addr.count(client) == 0) {
	dout(7) << " client" << client << " not mounted" << dendl;
	_unmounted((MClientUnmount*)m);
	return true;
      }
    }
    return false;

  default:
    assert(0);
    delete m;
    return true;
  }
}

bool ClientMonitor::prepare_update(Message *m)
{
  dout(10) << "prepare_update " << *m << " from " << m->get_source_inst() << dendl;

  switch (m->get_type()) {
  case CEPH_MSG_CLIENT_MOUNT:
    {
      entity_addr_t addr = m->get_source_addr();
      int client = -1;
      if (m->get_source().is_client())
	client = m->get_source().num();

      // choose a client id
      if (client < 0) {
	client = pending_inc.next_client;
	dout(10) << "mount: assigned client" << client << " to " << addr << dendl;
      } else {
	dout(10) << "mount: client" << client << " requested by " << addr << dendl;
	if (client_map.client_addr.count(client)) {
	  assert(client_map.client_addr[client] != addr);
	  dout(0) << "mount: WARNING: client" << client << " requested by " << addr
		  << ", which used to be "  << client_map.client_addr[client] << dendl;
	}
      }

      pending_inc.add_mount(client, addr);
      paxos->wait_for_commit(new C_Mounted(this, client, (MClientMount*)m));
    }
    return true;

  case CEPH_MSG_CLIENT_UNMOUNT:
    {
      assert(m->get_source().is_client());
      int client = m->get_source().num();

      assert(client_map.client_addr.count(client));

      pending_inc.add_unmount(client);
      paxos->wait_for_commit(new C_Unmounted(this, (MClientUnmount*)m));
    }
    return true;

  default:
    assert(0);
    delete m;
    return false;
  }

}

// MOUNT

void ClientMonitor::_mounted(int client, MClientMount *m)
{
  entity_inst_t to;
  to.addr = m->get_source_addr();
  to.name = entity_name_t::CLIENT(client);

  dout(10) << "_mounted client" << client << " at " << to << dendl;

  // reply with latest mon, mds, osd maps
  bufferlist bl;
  mon->monmap->encode(bl);
  mon->messenger->send_message(new MMonMap(bl), to);

  mon->mdsmon->send_latest(to);
  mon->osdmon->send_latest(to);

  delete m;
}

void ClientMonitor::_unmounted(MClientUnmount *m)
{
  dout(10) << "_unmounted " << m->get_source_inst() << dendl;

  // reply with (same) unmount message
  mon->messenger->send_message(m, m->get_source_inst());

  // auto-shutdown?
  // (hack for fakesyn/newsyn, mostly)
  if (mon->is_leader() &&
      client_map.version > 1 &&
      client_map.client_addr.empty() &&
      g_conf.mon_stop_on_last_unmount &&
      !mon->is_stopping()) {
    dout(1) << "last client unmounted" << dendl;
    mon->do_stop();
  }
}

<|endoftext|>


<commit_before>#include <meta_data_indexer.hpp>

#include <meta_data_parser.hpp>

#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/wave.hpp>

#include <iostream>

struct block {
    int level;
    std::string name;
    bool keep;
};

void print(const enum_delecration& parent, std::size_t level)
{
    std::string indent(4 * level, ' ');
    std::cout << indent << "enum " << parent.name << std::endl;
    std::cout << indent << "{" << std::endl;
    std::cout << boost::join(parent.values | boost::adaptors::transformed([indent](const auto& value) { return indent + std::string(4, ' ') + value; }), ",\n") << std::endl;
    std::cout << indent << "}" << std::endl;
}

void print(const property_delecration& parent, std::size_t level)
{
    std::string indent(4 * level, ' ');
    std::cout << indent << parent.type << " " << parent.name << ";" << std::endl;
}

void print(const class_delecration& parent, std::size_t level)
{
    std::string indent(4 * level, ' ');
    std::cout << indent << "class " << parent.name << std::endl;
    std::cout << indent << "{" << std::endl;
    for (const auto& e : parent.enums)
        print(e, level + 1);
    for (const auto& kl : parent.classes)
        print(kl, level + 1);
    for (const auto& p : parent.properties)
        print(p, level + 1);
    std::cout << indent << "}" << std::endl;
}

void print(const namespace_delecration& parent, std::size_t level)
{
    std::string indent(4 * level, ' ');
    std::cout << indent << "namespace " << parent.name << std::endl;
    std::cout << indent << "{" << std::endl;
    for (const auto& e : parent.enums)
        print(e, level + 1);
    for (const auto& kl : parent.classes)
        print(kl, level + 1);
    for (const auto& ns : parent.namespaces)
        print(ns);
    std::cout << indent << "}" << std::endl;
}

void print(const translation_unit& parent, std::size_t level)
{
    for (const auto& e : parent.enums)
        print(e, level);
    for (const auto& kl : parent.classes)
        print(kl, level);
    for (const auto& ns : parent.namespaces)
        print(ns, level);
}

template <typename T>
void merge_by_name(T& dest, const T& src)
{
    for (const auto& src_elem : src) {
        auto it = std::find_if(std::begin(dest), std::end(dest), [&src_elem](auto dest_elem) {
            return src_elem.name == dest_elem.name;
        });
        if (it != std::end(dest))
            merge(*it, src_elem);
        else
            dest.push_back(src_elem);
    }
}

void merge(enum_delecration& dest, const enum_delecration& src)
{
    // TODO error more than one definition of enum
}

void merge(class_delecration& dest, const class_delecration& src)
{
    // TODO error more than one definition of class
}

void merge(namespace_delecration& dest, const namespace_delecration& src)
{
    merge_by_name(dest.enums, src.enums);
    merge_by_name(dest.classes, src.classes);
    merge_by_name(dest.namespaces, src.namespaces);
}

void merge(translation_unit& dest, const translation_unit& src)
{
    merge_by_name(dest.enums, src.enums);
    merge_by_name(dest.classes, src.classes);
    merge_by_name(dest.namespaces, src.namespaces);
}

bool not_whitespace(const token_type& token)
{
    return !IS_CATEGORY(token, boost::wave::WhiteSpaceTokenType) && !IS_CATEGORY(token, boost::wave::EOLTokenType);
}

bool meta_data_indexer::index(boost::filesystem::path path)
{
    meta_data_parser parser;

    std::ifstream instream(path.string());
    if (instream.is_open()) {
        std::vector<token_type> input_tokens;
        try {
            instream.unsetf(std::ios::skipws);
            std::string instr = std::string(std::istreambuf_iterator<char>(instream.rdbuf()), std::istreambuf_iterator<char>());

            position_type pos(path.string().c_str());
            lexer_type token_begin = lexer_type(instr.begin(), instr.end(), pos, boost::wave::language_support(boost::wave::support_cpp | boost::wave::support_option_long_long));
            lexer_type token_end = lexer_type();

            std::copy_if(token_begin, token_end, std::back_inserter(input_tokens), not_whitespace);
        } catch (boost::wave::cpplexer::lexing_exception& e) {
            std::cerr << e.file_name() << ":" << e.line_no() << ":" << e.column_no() << " " << e.description() << std::endl;
            return false;
        } catch (std::exception& e) {
            std::cerr << e.what() << std::endl;
            return false;
        } catch (...) {
            std::cerr << "unexpected exception caught." << std::endl;
            return false;
        }

        if (!input_tokens.empty()) {
            try {
                translation_unit tu = parser.parse_translation_unit(input_tokens);
                merge(global_translation_unit_, tu);
            } catch (std::exception& e) {
                std::cerr << e.what() << std::endl;
                return false;
            }
        }
    } else {
        std::cerr << "Could not open input file: " << path << std::endl;
        return false;
    }
    return true;
}

void meta_data_indexer::print()
{
    ::print(global_translation_unit_);
}
<commit_msg>boost/wave.hpp does not compile one windows.<commit_after>#include <meta_data_indexer.hpp>

#include <meta_data_parser.hpp>

#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/wave/cpplexer/cpplexer_exceptions.hpp>

#include <iostream>
#include <fstream>

struct block {
    int level;
    std::string name;
    bool keep;
};

void print(const enum_delecration& parent, std::size_t level)
{
    std::string indent(4 * level, ' ');
    std::cout << indent << "enum " << parent.name << std::endl;
    std::cout << indent << "{" << std::endl;
    std::cout << boost::join(parent.values | boost::adaptors::transformed([indent](const auto& value) { return indent + std::string(4, ' ') + value; }), ",\n") << std::endl;
    std::cout << indent << "}" << std::endl;
}

void print(const property_delecration& parent, std::size_t level)
{
    std::string indent(4 * level, ' ');
    std::cout << indent << parent.type << " " << parent.name << ";" << std::endl;
}

void print(const class_delecration& parent, std::size_t level)
{
    std::string indent(4 * level, ' ');
    std::cout << indent << "class " << parent.name << std::endl;
    std::cout << indent << "{" << std::endl;
    for (const auto& e : parent.enums)
        print(e, level + 1);
    for (const auto& kl : parent.classes)
        print(kl, level + 1);
    for (const auto& p : parent.properties)
        print(p, level + 1);
    std::cout << indent << "}" << std::endl;
}

void print(const namespace_delecration& parent, std::size_t level)
{
    std::string indent(4 * level, ' ');
    std::cout << indent << "namespace " << parent.name << std::endl;
    std::cout << indent << "{" << std::endl;
    for (const auto& e : parent.enums)
        print(e, level + 1);
    for (const auto& kl : parent.classes)
        print(kl, level + 1);
    for (const auto& ns : parent.namespaces)
        print(ns);
    std::cout << indent << "}" << std::endl;
}

void print(const translation_unit& parent, std::size_t level)
{
    for (const auto& e : parent.enums)
        print(e, level);
    for (const auto& kl : parent.classes)
        print(kl, level);
    for (const auto& ns : parent.namespaces)
        print(ns, level);
}

template <typename T>
void merge_by_name(T& dest, const T& src)
{
    for (const auto& src_elem : src) {
        auto it = std::find_if(std::begin(dest), std::end(dest), [&src_elem](auto dest_elem) {
            return src_elem.name == dest_elem.name;
        });
        if (it != std::end(dest))
            merge(*it, src_elem);
        else
            dest.push_back(src_elem);
    }
}

void merge(enum_delecration& dest, const enum_delecration& src)
{
    // TODO error more than one definition of enum
}

void merge(class_delecration& dest, const class_delecration& src)
{
    // TODO error more than one definition of class
}

void merge(namespace_delecration& dest, const namespace_delecration& src)
{
    merge_by_name(dest.enums, src.enums);
    merge_by_name(dest.classes, src.classes);
    merge_by_name(dest.namespaces, src.namespaces);
}

void merge(translation_unit& dest, const translation_unit& src)
{
    merge_by_name(dest.enums, src.enums);
    merge_by_name(dest.classes, src.classes);
    merge_by_name(dest.namespaces, src.namespaces);
}

bool not_whitespace(const token_type& token)
{
    return !IS_CATEGORY(token, boost::wave::WhiteSpaceTokenType) && !IS_CATEGORY(token, boost::wave::EOLTokenType);
}

bool meta_data_indexer::index(boost::filesystem::path path)
{
    meta_data_parser parser;

    std::ifstream instream(path.string());
    if (instream.is_open()) {
        std::vector<token_type> input_tokens;
        try {
            instream.unsetf(std::ios::skipws);
            std::string instr = std::string(std::istreambuf_iterator<char>(instream.rdbuf()), std::istreambuf_iterator<char>());

            position_type pos(path.string().c_str());
            lexer_type token_begin = lexer_type(instr.begin(), instr.end(), pos, boost::wave::language_support(boost::wave::support_cpp | boost::wave::support_option_long_long));
            lexer_type token_end = lexer_type();

            std::copy_if(token_begin, token_end, std::back_inserter(input_tokens), not_whitespace);
        } catch (boost::wave::cpplexer::lexing_exception& e) {
            std::cerr << e.file_name() << ":" << e.line_no() << ":" << e.column_no() << " " << e.description() << std::endl;
            return false;
        } catch (std::exception& e) {
            std::cerr << e.what() << std::endl;
            return false;
        } catch (...) {
            std::cerr << "unexpected exception caught." << std::endl;
            return false;
        }

        if (!input_tokens.empty()) {
            try {
                translation_unit tu = parser.parse_translation_unit(input_tokens);
                merge(global_translation_unit_, tu);
            } catch (std::exception& e) {
                std::cerr << e.what() << std::endl;
                return false;
            }
        }
    } else {
        std::cerr << "Could not open input file: " << path << std::endl;
        return false;
    }
    return true;
}

void meta_data_indexer::print()
{
    ::print(global_translation_unit_);
}<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd/object.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/evaluate.hpp"
#include "flusspferd/value_io.hpp"
#include "flusspferd/property_iterator.hpp"
#include "test_environment.hpp"

BOOST_TEST_DONT_PRINT_LOG_VALUE(flusspferd::object) //FIXME?

BOOST_FIXTURE_TEST_SUITE( with_context, context_fixture )

BOOST_AUTO_TEST_CASE( null_object ) {
  flusspferd::object null_object;
  BOOST_CHECK(null_object.is_null());

  BOOST_CHECK_EQUAL(null_object, null_object);

  flusspferd::object object_copy(null_object);
  BOOST_CHECK(null_object.is_null());

  BOOST_CHECK_EQUAL(null_object, object_copy);
}

BOOST_AUTO_TEST_CASE( plain_object ) {
  flusspferd::object const &plain_object = flusspferd::create_object();
  BOOST_CHECK(!plain_object.is_null());

  BOOST_CHECK_EQUAL(plain_object, plain_object);
  BOOST_CHECK_NE(plain_object, flusspferd::object());

  flusspferd::object object_copy(plain_object);
  BOOST_CHECK(!object_copy.is_null());

  BOOST_CHECK_EQUAL(plain_object, object_copy);

  flusspferd::object const &plain_object2 = flusspferd::create_object();
  BOOST_CHECK_NE(plain_object, plain_object2);
}

BOOST_AUTO_TEST_CASE( object_property ) {
  flusspferd::object obj = flusspferd::create_object();
  std::string const name = "foobar";
  flusspferd::value const v(409);
  obj.set_property(name, v);
  BOOST_CHECK(obj.has_property(name));
  BOOST_CHECK_EQUAL(obj.get_property(name), v);
  obj.delete_property(name);
  BOOST_CHECK(!obj.has_property(name));
  flusspferd::value const empty;
  BOOST_CHECK_EQUAL(obj.get_property(name), empty);
}

BOOST_AUTO_TEST_CASE( object_property_value ) {
  flusspferd::object obj = flusspferd::create_object();
  flusspferd::value const name = flusspferd::string("foobar");
  flusspferd::value const v(409);
  obj.set_property(name, v);
  BOOST_CHECK(obj.has_property(name));
  BOOST_CHECK_EQUAL(obj.get_property(name), v);
  obj.delete_property(name);
  BOOST_CHECK(!obj.has_property(name));
  flusspferd::value const empty;
  BOOST_CHECK_EQUAL(obj.get_property(name), empty);
}

BOOST_AUTO_TEST_CASE( function_as_object ) {
  flusspferd::value v = flusspferd::evaluate("(function () {})");
  BOOST_CHECK(!v.is_undefined());
  BOOST_CHECK(v.is_object());
  BOOST_CHECK(!v.is_null());
}

BOOST_AUTO_TEST_CASE( call_on_invalid ) {
  flusspferd::object invalid_object;
  BOOST_REQUIRE(invalid_object.is_null());

  flusspferd::object &obj = invalid_object;

#define X(a) BOOST_CHECK_THROW((a), flusspferd::exception)

  X(obj.seal(true));
  X(obj.parent());
  X(obj.prototype());
  X(obj.set_parent(flusspferd::object()));
  X(obj.set_prototype(flusspferd::object()));
  X((obj.apply(flusspferd::global(), flusspferd::arguments())))
  X((obj.call("toString", flusspferd::arguments())));
  X((obj.call(flusspferd::global(), flusspferd::arguments())));
  X(obj.call(flusspferd::arguments()));
  X(obj.define_property("abc"));
  X(obj.define_property(flusspferd::string()));
  X(obj.define_property(std::string("abc")));
  X(obj.set_property("abc", flusspferd::value()));
  X(obj.set_property(flusspferd::value(3), flusspferd::value()));
  X(obj.set_property(std::string("abc"), flusspferd::value()));
  X(obj.get_property("abc"));
  X(obj.get_property(std::string("abc")));
  X(obj.get_property(flusspferd::value(3)));
  X(obj.has_property("abc"));
  X(obj.has_property(std::string("abc")));
  X(obj.has_property(flusspferd::value(3)));
  X(obj.has_own_property("abc"));
  X(obj.has_own_property(std::string("abc")));
  X(obj.has_own_property(flusspferd::value(3)));
  X(obj.delete_property("abc"));
  X(obj.delete_property(std::string("abc")));
  X(obj.delete_property(flusspferd::value(3)));
  X(obj.begin());
  X(obj.end());
  BOOST_CHECK_EQUAL(obj.is_array(), false);

  flusspferd::property_attributes dummy;
  X(obj.get_property_attributes("abc", dummy));
  X(obj.get_property_attributes(std::string("abc"), dummy));
  X(obj.get_property_attributes(flusspferd::string(), dummy));

  //TODO
#undef X
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Added test case for issue #110<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "flusspferd/object.hpp"
#include "flusspferd/create.hpp"
#include "flusspferd/evaluate.hpp"
#include "flusspferd/value_io.hpp"
#include "flusspferd/property_iterator.hpp"
#include "test_environment.hpp"

BOOST_TEST_DONT_PRINT_LOG_VALUE(flusspferd::object) //FIXME?

BOOST_FIXTURE_TEST_SUITE( with_context, context_fixture )

BOOST_AUTO_TEST_CASE( null_object ) {
  flusspferd::object null_object;
  BOOST_CHECK(null_object.is_null());

  BOOST_CHECK_EQUAL(null_object, null_object);

  flusspferd::object object_copy(null_object);
  BOOST_CHECK(null_object.is_null());

  BOOST_CHECK_EQUAL(null_object, object_copy);
}

BOOST_AUTO_TEST_CASE( plain_object ) {
  flusspferd::object const &plain_object = flusspferd::create_object();
  BOOST_CHECK(!plain_object.is_null());

  BOOST_CHECK_EQUAL(plain_object, plain_object);
  BOOST_CHECK_NE(plain_object, flusspferd::object());

  flusspferd::object object_copy(plain_object);
  BOOST_CHECK(!object_copy.is_null());

  BOOST_CHECK_EQUAL(plain_object, object_copy);

  flusspferd::object const &plain_object2 = flusspferd::create_object();
  BOOST_CHECK_NE(plain_object, plain_object2);
}

BOOST_AUTO_TEST_CASE( object_property ) {
  flusspferd::object obj = flusspferd::create_object();
  std::string const name = "foobar";
  flusspferd::value const v(409);
  obj.set_property(name, v);
  BOOST_CHECK(obj.has_property(name));
  BOOST_CHECK_EQUAL(obj.get_property(name), v);
  obj.delete_property(name);
  BOOST_CHECK(!obj.has_property(name));
  flusspferd::value const empty;
  BOOST_CHECK_EQUAL(obj.get_property(name), empty);
}

BOOST_AUTO_TEST_CASE( object_property_value ) {
  flusspferd::object obj = flusspferd::create_object();
  flusspferd::value const name = flusspferd::string("foobar");
  flusspferd::value const v(409);
  obj.set_property(name, v);
  BOOST_CHECK(obj.has_property(name));
  BOOST_CHECK_EQUAL(obj.get_property(name), v);
  obj.delete_property(name);
  BOOST_CHECK(!obj.has_property(name));
  flusspferd::value const empty;
  BOOST_CHECK_EQUAL(obj.get_property(name), empty);
}

BOOST_AUTO_TEST_CASE( function_as_object ) {
  flusspferd::value v = flusspferd::evaluate("(function () {})");
  BOOST_CHECK(!v.is_undefined());
  BOOST_CHECK(v.is_object());
  BOOST_CHECK(!v.is_null());
}

BOOST_AUTO_TEST_CASE( call_on_invalid ) {
  flusspferd::object invalid_object;
  BOOST_REQUIRE(invalid_object.is_null());

  flusspferd::object &obj = invalid_object;

#define X(a) BOOST_CHECK_THROW((a), flusspferd::exception)

  X(obj.seal(true));
  X(obj.parent());
  X(obj.prototype());
  X(obj.set_parent(flusspferd::object()));
  X(obj.set_prototype(flusspferd::object()));
  X((obj.apply(flusspferd::global(), flusspferd::arguments())))
  X((obj.call("toString", flusspferd::arguments())));
  X((obj.call(flusspferd::global(), flusspferd::arguments())));
  X(obj.call(flusspferd::arguments()));
  X(obj.define_property("abc"));
  X(obj.define_property(flusspferd::string()));
  X(obj.define_property(std::string("abc")));
  X(obj.set_property("abc", flusspferd::value()));
  X(obj.set_property(flusspferd::value(3), flusspferd::value()));
  X(obj.set_property(std::string("abc"), flusspferd::value()));
  X(obj.get_property("abc"));
  X(obj.get_property(std::string("abc")));
  X(obj.get_property(flusspferd::value(3)));
  X(obj.has_property("abc"));
  X(obj.has_property(std::string("abc")));
  X(obj.has_property(flusspferd::value(3)));
  X(obj.has_own_property("abc"));
  X(obj.has_own_property(std::string("abc")));
  X(obj.has_own_property(flusspferd::value(3)));
  X(obj.delete_property("abc"));
  X(obj.delete_property(std::string("abc")));
  X(obj.delete_property(flusspferd::value(3)));
  X(obj.begin());
  X(obj.end());
  BOOST_CHECK_EQUAL(obj.is_array(), false);

  flusspferd::property_attributes dummy;
  X(obj.get_property_attributes("abc", dummy));
  X(obj.get_property_attributes(std::string("abc"), dummy));
  X(obj.get_property_attributes(flusspferd::string(), dummy));

  //TODO
#undef X
}

BOOST_AUTO_TEST_CASE( recursive_loop_on_set_property ) {
  flusspferd::object object = flusspferd::create_object();

  object.set_property( flusspferd::string(), flusspferd::string() );

}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "utest.hpp"
#include "tensor.h"
#include "math/random.hpp"
#include "opencl/opencl.h"
#include "opencl/kernels.h"
#include "math/epsilon.hpp"
#include "tensor/numeric.hpp"

using namespace nano;

auto rng_size = nano::make_rng<tensor_size_t>(1, 1024);
auto rng_value = nano::make_rng<scalar_t>(-1, +1);

NANO_BEGIN_MODULE(test_opencl)

NANO_CASE(addv)
{
        opencl_manager_t theocl;
        NANO_REQUIRE_NOTHROW(theocl.init());
        NANO_REQUIRE_NOTHROW(theocl.select(CL_DEVICE_TYPE_GPU));

        cl::Program program;
        NANO_REQUIRE_NOTHROW(theocl.make_program_from_text(opencl_kernel_addv()));

        cl::Kernel kernel;
        NANO_REQUIRE_NOTHROW(theocl.make_kernel(program, "addv"));

        for (int test = 0; test < 11; ++ test)
        {
                const auto dims = rng_size();

                vector_t x(dims), y(dims), z(dims);
                tensor::set_random(rng_value, x, y, z);

                cl::Buffer xbuffer = theocl.make_buffer(tensor_size(x), CL_MEM_READ_WRITE);
                cl::Buffer ybuffer = theocl.make_buffer(tensor_size(y), CL_MEM_READ_WRITE);
                cl::Buffer zbuffer = theocl.make_buffer(tensor_size(z), CL_MEM_READ_ONLY);

                kernel.setArg(0, xbuffer);
                kernel.setArg(1, ybuffer);
                kernel.setArg(2, zbuffer);

                cl::CommandQueue& queue = theocl.command_queue();
                queue.enqueueWriteBuffer(xbuffer, CL_FALSE, 0, tensor_size(x), x.data());
                queue.enqueueWriteBuffer(ybuffer, CL_FALSE, 0, tensor_size(y), y.data());
                queue.finish();

                queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(size_t(dims)), cl::NullRange);
                queue.finish();

                queue.enqueueReadBuffer(zbuffer, CL_TRUE, 0, tensor_size(z), z.data());
                NANO_CHECK_EIGEN_CLOSE((x + y), z, nano::epsilon0<scalar_t>());
        }
}

NANO_END_MODULE()
<commit_msg>fix unit test<commit_after>#include "utest.hpp"
#include "tensor.h"
#include "math/random.hpp"
#include "opencl/opencl.h"
#include "opencl/kernels.h"
#include "math/epsilon.hpp"
#include "tensor/numeric.hpp"

using namespace nano;

auto rng_size = nano::make_rng<tensor_size_t>(1, 1024);
auto rng_value = nano::make_rng<scalar_t>(-1, +1);

NANO_BEGIN_MODULE(test_opencl)

NANO_CASE(addv)
{
        opencl_manager_t theocl;
        NANO_REQUIRE_NOTHROW(theocl.init());
        NANO_REQUIRE_NOTHROW(theocl.select(CL_DEVICE_TYPE_GPU));

        cl::Program program;
        NANO_REQUIRE_NOTHROW(program = theocl.make_program_from_text(opencl_kernel_addv()));

        cl::Kernel kernel;
        NANO_REQUIRE_NOTHROW(kernel = theocl.make_kernel(program, "addv"));

        for (int test = 0; test < 11; ++ test)
        {
                const auto dims = rng_size();

                vector_t x(dims), y(dims), z(dims);
                tensor::set_random(rng_value, x, y, z);

                cl::Buffer xbuffer = theocl.make_buffer(tensor_size(x), CL_MEM_READ_WRITE);
                cl::Buffer ybuffer = theocl.make_buffer(tensor_size(y), CL_MEM_READ_WRITE);
                cl::Buffer zbuffer = theocl.make_buffer(tensor_size(z), CL_MEM_READ_ONLY);

                kernel.setArg(0, xbuffer);
                kernel.setArg(1, ybuffer);
                kernel.setArg(2, zbuffer);

                cl::CommandQueue& queue = theocl.command_queue();
                queue.enqueueWriteBuffer(xbuffer, CL_FALSE, 0, tensor_size(x), x.data());
                queue.enqueueWriteBuffer(ybuffer, CL_FALSE, 0, tensor_size(y), y.data());
                queue.finish();

                queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(size_t(dims)), cl::NullRange);
                queue.finish();

                queue.enqueueReadBuffer(zbuffer, CL_TRUE, 0, tensor_size(z), z.data());
                NANO_CHECK_EIGEN_CLOSE((x + y), z, nano::epsilon0<scalar_t>());
        }
}

NANO_END_MODULE()
<|endoftext|>


<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/compiler/xla/service/interpreter/executable.h"

#include <algorithm>
#include <cstring>
#include <string>
#include <utility>
#include <vector>

#include "absl/memory/memory.h"
#include "tensorflow/compiler/xla/literal.h"
#include "tensorflow/compiler/xla/service/hlo_computation.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/interpreter/executor.h"
#include "tensorflow/compiler/xla/service/maybe_owning_device_memory.h"
#include "tensorflow/compiler/xla/service/transfer_manager.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/compiler/xla/status_macros.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/stream_executor_no_cuda.h"

namespace xla {
namespace interpreter {

InterpreterExecutable::InterpreterExecutable(
    std::unique_ptr<HloModule> hlo_module,
    std::unique_ptr<HloEvaluator> evaluator)
    : Executable(std::move(hlo_module), /*hlo_profile_printer_data=*/nullptr,
                 /*hlo_profile_index_map=*/nullptr),
      evaluator_(std::move(evaluator)) {}

InterpreterExecutable::~InterpreterExecutable() {}

StatusOr<ExecutionOutput> InterpreterExecutable::ExecuteAsyncOnStream(
    const ServiceExecutableRunOptions* run_options,
    std::vector<ShapeTree<MaybeOwningDeviceMemory>> arguments,
    HloExecutionProfile* hlo_execution_profile) {
  se::Stream* stream = run_options->stream();
  se::StreamExecutor* executor = stream->parent();
  const se::Platform* platform = executor->platform();

  // Convert the ShapeTree to a ShapedBuffer. We do this so we can call
  // TransferManager methods below.
  std::vector<ShapedBuffer> argument_buffers;
  argument_buffers.reserve(arguments.size());
  for (const ShapeTree<MaybeOwningDeviceMemory>& arg : arguments) {
    argument_buffers.push_back(ShapedBuffer(arg.shape(), arg.shape(),
                                            /*platform=*/nullptr,
                                            /*device_ordinal=*/0));
    auto in_it = arg.begin();
    auto out_it = argument_buffers.back().buffers().begin();
    for (; in_it != arg.end(); ++in_it, ++out_it) {
      out_it->second = in_it->second.AsDeviceMemoryBase();
    }
  }

  VLOG(1) << "Execute " << module().name();
  if (VLOG_IS_ON(2)) {
    for (const auto& a : argument_buffers) {
      VLOG(2) << "-- argument " << a;
    }
  }

  uint64 start_micros = tensorflow::Env::Default()->NowMicros();

  const HloComputation* computation = module().entry_computation();
  if (computation->num_parameters() != arguments.size()) {
    return tensorflow::errors::Internal(
        "Mismatch between argument count and graph parameter count.");
  }

  // Check that the args have the right shape.
  for (int64 i = 0; i < computation->num_parameters(); ++i) {
    const auto& expected_shape = computation->parameter_instruction(i)->shape();
    const auto& actual_shape = argument_buffers[i].on_device_shape();
    if (!Shape::Equal().MinorToMajorOnlyInLayout()(expected_shape,
                                                   actual_shape)) {
      return InvalidArgument(
          "Shape mismatch on parameter %d.  Expected %s, but was %s.", i,
          ShapeUtil::HumanStringWithLayout(expected_shape),
          ShapeUtil::HumanStringWithLayout(actual_shape));
    }
  }

  TF_ASSIGN_OR_RETURN(TransferManager * transfer_manager,
                      TransferManager::GetForPlatform(platform));

  // Transform the ShapedBuffer arguments into literals which the evaluator
  // consumes.
  std::vector<Literal> arg_literals;
  for (int64 p = 0; p < computation->num_parameters(); ++p) {
    TF_ASSIGN_OR_RETURN(Literal arg_literal,
                        transfer_manager->TransferLiteralFromDevice(
                            run_options->stream(), argument_buffers[p]));
    arg_literals.push_back(std::move(arg_literal));
  }

  // Execute the graph using the HloEvaluator.
  Literal result_literal;
  {
    tensorflow::mutex_lock lock(evaluator_lock_);
    evaluator_->ResetVisitStates();
    TF_ASSIGN_OR_RETURN(result_literal,
                        evaluator_->Evaluate(*computation, arg_literals));
  }

  // Transform the result literal back into a ShapedBuffer.
  TF_ASSIGN_OR_RETURN(ScopedShapedBuffer result,
                      transfer_manager->AllocateScopedShapedBuffer(
                          result_literal.shape(), run_options->allocator(),
                          executor->device_ordinal()));
  TF_RETURN_IF_ERROR(transfer_manager->TransferLiteralToDevice(
      run_options->stream(), result_literal, result));

  uint64 end_micros = tensorflow::Env::Default()->NowMicros();

  ExecutionProfile* profile = run_options->run_options().execution_profile();
  if (profile) {
    const double nanoseconds = (end_micros - start_micros) * 1000.0;
    profile->set_compute_time_ns(std::max(nanoseconds, 1.0));
  }

  std::vector<se::OwningDeviceMemory> buffers_to_free;
  for (ShapeTree<MaybeOwningDeviceMemory>& argument : arguments) {
    for (std::pair<ShapeIndex, MaybeOwningDeviceMemory>& buffer : argument) {
      auto maybe_owning_buffer = buffer.second.Release();
      if (maybe_owning_buffer) {
        buffers_to_free.push_back(std::move(*maybe_owning_buffer));
      }
    }
  }
  return ExecutionOutput(std::move(result), std::move(buffers_to_free), {}, {});
}

/*static*/ int64 InterpreterExecutable::ShapeSizeBytes(const Shape& shape) {
  if (shape.IsOpaque()) {
    return sizeof(void*);
  }
  return ShapeUtil::ByteSizeOf(shape, sizeof(void*));
}

}  // namespace interpreter
}  // namespace xla
<commit_msg>Fixing xla executable buffer creation<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/compiler/xla/service/interpreter/executable.h"

#include <algorithm>
#include <cstring>
#include <string>
#include <utility>
#include <vector>

#include "absl/memory/memory.h"
#include "tensorflow/compiler/xla/literal.h"
#include "tensorflow/compiler/xla/service/hlo_computation.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/interpreter/executor.h"
#include "tensorflow/compiler/xla/service/maybe_owning_device_memory.h"
#include "tensorflow/compiler/xla/service/transfer_manager.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/compiler/xla/status_macros.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/stream_executor_no_cuda.h"

namespace xla {
namespace interpreter {

InterpreterExecutable::InterpreterExecutable(
    std::unique_ptr<HloModule> hlo_module,
    std::unique_ptr<HloEvaluator> evaluator)
    : Executable(std::move(hlo_module), /*hlo_profile_printer_data=*/nullptr,
                 /*hlo_profile_index_map=*/nullptr),
      evaluator_(std::move(evaluator)) {}

InterpreterExecutable::~InterpreterExecutable() {}

StatusOr<ExecutionOutput> InterpreterExecutable::ExecuteAsyncOnStream(
    const ServiceExecutableRunOptions* run_options,
    std::vector<ShapeTree<MaybeOwningDeviceMemory>> arguments,
    HloExecutionProfile* hlo_execution_profile) {
  se::Stream* stream = run_options->stream();
  se::StreamExecutor* executor = stream->parent();
  const se::Platform* platform = executor->platform();

  // Convert the ShapeTree to a ShapedBuffer. We do this so we can call
  // TransferManager methods below.
  std::vector<ShapedBuffer> argument_buffers;
  argument_buffers.reserve(arguments.size());
  for (const ShapeTree<MaybeOwningDeviceMemory>& arg : arguments) {
    argument_buffers.push_back(
        ShapedBuffer(arg.shape(), arg.shape(),
                     /*platform=*/platform,
                     /*device_ordinal=*/executor->device_ordinal()));
    auto in_it = arg.begin();
    auto out_it = argument_buffers.back().buffers().begin();
    for (; in_it != arg.end(); ++in_it, ++out_it) {
      out_it->second = in_it->second.AsDeviceMemoryBase();
    }
  }

  VLOG(1) << "Execute " << module().name();
  if (VLOG_IS_ON(2)) {
    for (const auto& a : argument_buffers) {
      VLOG(2) << "-- argument " << a;
    }
  }

  uint64 start_micros = tensorflow::Env::Default()->NowMicros();

  const HloComputation* computation = module().entry_computation();
  if (computation->num_parameters() != arguments.size()) {
    return tensorflow::errors::Internal(
        "Mismatch between argument count and graph parameter count.");
  }

  // Check that the args have the right shape.
  for (int64 i = 0; i < computation->num_parameters(); ++i) {
    const auto& expected_shape = computation->parameter_instruction(i)->shape();
    const auto& actual_shape = argument_buffers[i].on_device_shape();
    if (!Shape::Equal().MinorToMajorOnlyInLayout()(expected_shape,
                                                   actual_shape)) {
      return InvalidArgument(
          "Shape mismatch on parameter %d.  Expected %s, but was %s.", i,
          ShapeUtil::HumanStringWithLayout(expected_shape),
          ShapeUtil::HumanStringWithLayout(actual_shape));
    }
  }

  TF_ASSIGN_OR_RETURN(TransferManager * transfer_manager,
                      TransferManager::GetForPlatform(platform));

  // Transform the ShapedBuffer arguments into literals which the evaluator
  // consumes.
  std::vector<Literal> arg_literals;
  for (int64 p = 0; p < computation->num_parameters(); ++p) {
    TF_ASSIGN_OR_RETURN(Literal arg_literal,
                        transfer_manager->TransferLiteralFromDevice(
                            run_options->stream(), argument_buffers[p]));
    arg_literals.push_back(std::move(arg_literal));
  }

  // Execute the graph using the HloEvaluator.
  Literal result_literal;
  {
    tensorflow::mutex_lock lock(evaluator_lock_);
    evaluator_->ResetVisitStates();
    TF_ASSIGN_OR_RETURN(result_literal,
                        evaluator_->Evaluate(*computation, arg_literals));
  }

  // Transform the result literal back into a ShapedBuffer.
  TF_ASSIGN_OR_RETURN(ScopedShapedBuffer result,
                      transfer_manager->AllocateScopedShapedBuffer(
                          result_literal.shape(), run_options->allocator(),
                          executor->device_ordinal()));
  TF_RETURN_IF_ERROR(transfer_manager->TransferLiteralToDevice(
      run_options->stream(), result_literal, result));

  uint64 end_micros = tensorflow::Env::Default()->NowMicros();

  ExecutionProfile* profile = run_options->run_options().execution_profile();
  if (profile) {
    const double nanoseconds = (end_micros - start_micros) * 1000.0;
    profile->set_compute_time_ns(std::max(nanoseconds, 1.0));
  }

  std::vector<se::OwningDeviceMemory> buffers_to_free;
  for (ShapeTree<MaybeOwningDeviceMemory>& argument : arguments) {
    for (std::pair<ShapeIndex, MaybeOwningDeviceMemory>& buffer : argument) {
      auto maybe_owning_buffer = buffer.second.Release();
      if (maybe_owning_buffer) {
        buffers_to_free.push_back(std::move(*maybe_owning_buffer));
      }
    }
  }
  return ExecutionOutput(std::move(result), std::move(buffers_to_free), {}, {});
}

/*static*/ int64 InterpreterExecutable::ShapeSizeBytes(const Shape& shape) {
  if (shape.IsOpaque()) {
    return sizeof(void*);
  }
  return ShapeUtil::ByteSizeOf(shape, sizeof(void*));
}

}  // namespace interpreter
}  // namespace xla
<|endoftext|>


<commit_before>
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>

#include <cppassist/logging/logging.h>

#include <gloperate/gloperate.h>
#include <gloperate/base/Environment.h>
#include <gloperate/base/GLContextUtils.h>

#include <demo-stages/DemoStage.h>
#include <demo-stages/DemoPipeline.h>

#include <gloperate-qt/base/GLContext.h>
#include <gloperate-qt/base/Application.h>
#include <gloperate-qt/base/UpdateManager.h>
#include <gloperate-qt/base/RenderWindow.h>
#include <gloperate-qt/scripting/ECMA26251SyntaxHighlighter.h>
#include <gloperate-qt/scripting/ECMA26251Completer.h>
#include <gloperate-qt/scripting/ScriptPromptWidget.h>

using namespace gloperate;
using namespace gloperate_qt;

int main(int argc, char * argv[])
{
    // Create gloperate environment
    Environment environment;
    environment.setupScripting();

    // Configure and load plugins
    environment.componentManager()->addPluginPath(
        gloperate::pluginPath(), cppexpose::PluginPathType::Internal
    );
    environment.componentManager()->scanPlugins("loaders");
    environment.componentManager()->scanPlugins("stages");
    environment.componentManager()->scanPlugins("exporter");

    // Initialize Qt application
    gloperate_qt::Application app(&environment, argc, argv);
    UpdateManager updateManager(&environment);

    // Create render stage
    auto renderStage = cppassist::make_unique<gloperate::DemoStage>(&environment);

    // Create render window
    auto window = cppassist::make_unique<RenderWindow>(&environment);
    auto windowRaw = window.get();
    window->createContext();
    window->setRenderStage(std::move(renderStage));

    // Create main window
    QMainWindow mainWindow;
    mainWindow.setWindowTitle("gloperate viewer");
    mainWindow.resize(1280, 720);
    mainWindow.setCentralWidget(QWidget::createWindowContainer(window.release())); // pass ownership to Qt
    mainWindow.centralWidget()->setFocusPolicy(Qt::StrongFocus);
    mainWindow.show();

    // Create script console
    auto scriptPrompt = cppassist::make_unique<ScriptPromptWidget>(&mainWindow);
    scriptPrompt->setSyntaxHighlighter(cppassist::make_unique<ECMA26251SyntaxHighlighter>());
    scriptPrompt->setCompleter(cppassist::make_unique<ECMA26251Completer>());
    scriptPrompt->setFrameShape(QFrame::NoFrame);

    auto scriptPromptRaw = scriptPrompt.get();
    QObject::connect(scriptPrompt.get(), &ScriptPromptWidget::evaluate,
        [&environment, scriptPromptRaw] (const QString & cmd)
        {
            // Execute script code
            std::string code = cmd.toStdString();
            cppexpose::Variant res = environment.executeScript(code);

            // Output result
            scriptPromptRaw->print(QString::fromStdString(res.value<std::string>()));
        }
    );

    // Create dock window for scripting console
    auto scriptPromptDockWidget = cppassist::make_unique<QDockWidget>("Script Prompt");
    scriptPromptDockWidget->setWidget(scriptPrompt.release());
    scriptPromptDockWidget->setObjectName("ScriptPromptWidget");
    mainWindow.addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, scriptPromptDockWidget.release());

    // Initialize context, print context info
    windowRaw->context()->use();
//  windowRaw->context()->setSwapInterval(Context::SwapInterval::VerticalSyncronization);
    cppassist::info() << std::endl
        << "OpenGL Version:  " << GLContextUtils::version() << std::endl
        << "OpenGL Profile:  " << GLContextUtils::profile() << std::endl
        << "OpenGL Vendor:   " << GLContextUtils::vendor() << std::endl
        << "OpenGL Renderer: " << GLContextUtils::renderer() << std::endl;
    windowRaw->context()->release();

    // Run main loop
    return app.exec();
}
<commit_msg>Fix Qt example compilation<commit_after>
#include <QApplication>
#include <QMainWindow>
#include <QDockWidget>

#include <cppassist/logging/logging.h>

#include <gloperate/gloperate.h>
#include <gloperate/base/Environment.h>
#include <gloperate/base/GLContextUtils.h>
#include <gloperate/pipeline/Stage.h>

#include <gloperate-qt/base/GLContext.h>
#include <gloperate-qt/base/Application.h>
#include <gloperate-qt/base/UpdateManager.h>
#include <gloperate-qt/base/RenderWindow.h>
#include <gloperate-qt/scripting/ECMA26251SyntaxHighlighter.h>
#include <gloperate-qt/scripting/ECMA26251Completer.h>
#include <gloperate-qt/scripting/ScriptPromptWidget.h>

using namespace gloperate;
using namespace gloperate_qt;

int main(int argc, char * argv[])
{
    // Create gloperate environment
    Environment environment;
    environment.setupScripting();

    // Configure and load plugins
    environment.componentManager()->addPluginPath(
        gloperate::pluginPath(), cppexpose::PluginPathType::Internal
    );
    environment.componentManager()->scanPlugins("loaders");
    environment.componentManager()->scanPlugins("stages");
    environment.componentManager()->scanPlugins("exporter");

    // Initialize Qt application
    gloperate_qt::Application app(&environment, argc, argv);
    UpdateManager updateManager(&environment);

    // Create render stage
    auto renderStage = environment.componentManager()->component<Stage>("DemoStage")->createInstance(&environment);

    // Create render window
    auto window = cppassist::make_unique<RenderWindow>(&environment);
    auto windowRaw = window.get();
    window->createContext();
    window->setRenderStage(std::move(renderStage));

    // Create main window
    QMainWindow mainWindow;
    mainWindow.setWindowTitle("gloperate viewer");
    mainWindow.resize(1280, 720);
    mainWindow.setCentralWidget(QWidget::createWindowContainer(window.release())); // pass ownership to Qt
    mainWindow.centralWidget()->setFocusPolicy(Qt::StrongFocus);
    mainWindow.show();

    // Create script console
    auto scriptPrompt = cppassist::make_unique<ScriptPromptWidget>(&mainWindow);
    scriptPrompt->setSyntaxHighlighter(cppassist::make_unique<ECMA26251SyntaxHighlighter>());
    scriptPrompt->setCompleter(cppassist::make_unique<ECMA26251Completer>());
    scriptPrompt->setFrameShape(QFrame::NoFrame);

    auto scriptPromptRaw = scriptPrompt.get();
    QObject::connect(scriptPrompt.get(), &ScriptPromptWidget::evaluate,
        [&environment, scriptPromptRaw] (const QString & cmd)
        {
            // Execute script code
            std::string code = cmd.toStdString();
            cppexpose::Variant res = environment.executeScript(code);

            // Output result
            scriptPromptRaw->print(QString::fromStdString(res.value<std::string>()));
        }
    );

    // Create dock window for scripting console
    auto scriptPromptDockWidget = cppassist::make_unique<QDockWidget>("Script Prompt");
    scriptPromptDockWidget->setWidget(scriptPrompt.release());
    scriptPromptDockWidget->setObjectName("ScriptPromptWidget");
    mainWindow.addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, scriptPromptDockWidget.release());

    // Initialize context, print context info
    windowRaw->context()->use();
//  windowRaw->context()->setSwapInterval(Context::SwapInterval::VerticalSyncronization);
    cppassist::info() << std::endl
        << "OpenGL Version:  " << GLContextUtils::version() << std::endl
        << "OpenGL Profile:  " << GLContextUtils::profile() << std::endl
        << "OpenGL Vendor:   " << GLContextUtils::vendor() << std::endl
        << "OpenGL Renderer: " << GLContextUtils::renderer() << std::endl;
    windowRaw->context()->release();

    // Run main loop
    return app.exec();
}
<|endoftext|>


<commit_before>/* Copyright 2015 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/common_runtime/gpu/gpu_debug_allocator.h"

#include <cstddef>
#include <vector>

#include "tensorflow/core/common_runtime/gpu/gpu_id.h"
#include "tensorflow/core/common_runtime/gpu/gpu_id_utils.h"
#include "tensorflow/core/common_runtime/gpu/gpu_init.h"
#include "tensorflow/core/platform/stream_executor.h"

#define MASK_WORDS 2
#define MASK_BYTES (MASK_WORDS * sizeof(int64))

namespace tensorflow {
namespace {

int64* NewMask(int64 word) {
  int64* m = new int64[MASK_WORDS];
  for (int i = 0; i < MASK_WORDS; ++i) {
    m[i] = word;
  }
  return m;
}

int64* before_mask = NewMask(0xabababababababab);
int64* after_mask = NewMask(0xcdcdcdcdcdcdcdcd);

bool CheckMask(se::StreamExecutor* exec, void* ptr, int64* mask) {
  se::DeviceMemory<int64> gpu_ptr{se::DeviceMemoryBase{ptr, MASK_BYTES}};
  int64 tmp[MASK_WORDS];

  if (!exec->SynchronousMemcpy(&tmp, gpu_ptr, MASK_BYTES)) {
    LOG(FATAL) << "Could not copy debug mask";
  }

  bool ok = true;
  for (int i = 0; i < MASK_WORDS; ++i) {
    ok &= (mask[i] == tmp[i]);
    if (!ok) {
      LOG(ERROR) << "i=" << i
                 << " mask=" << reinterpret_cast<const void*>(mask[i])
                 << " field=" << reinterpret_cast<const void*>(tmp[i]);
    }
  }

  return ok;
}

void InitMask(se::StreamExecutor* exec, void* ptr, int64* mask) {
  se::DeviceMemory<int64> gpu_ptr{se::DeviceMemoryBase{ptr, MASK_BYTES}};
  if (!exec->SynchronousMemcpy(&gpu_ptr, mask, MASK_BYTES)) {
    LOG(FATAL) << "Could not copy debug mask";
  }
}

}  // namespace

// -----------------------------------------------------------------------------
// GPUDebugAllocator
// -----------------------------------------------------------------------------
GPUDebugAllocator::GPUDebugAllocator(Allocator* allocator,
                                     PlatformGpuId platform_gpu_id)
    : base_allocator_(allocator) {
  stream_exec_ =
      GpuIdUtil::ExecutorForPlatformGpuId(platform_gpu_id).ValueOrDie();
}

GPUDebugAllocator::~GPUDebugAllocator() { delete base_allocator_; }

void* GPUDebugAllocator::AllocateRaw(size_t alignment, size_t num_bytes) {
  num_bytes += (2 * MASK_BYTES);
  void* allocated_ptr = base_allocator_->AllocateRaw(alignment, num_bytes);
  if (allocated_ptr == nullptr) return allocated_ptr;

  // Return the pointer after the header
  void* rv = static_cast<char*>(allocated_ptr) + MASK_BYTES;

  // Write the header at allocated_ptr
  InitMask(stream_exec_, allocated_ptr, before_mask);

  // Write the footer at the end.
  size_t req_size = base_allocator_->RequestedSize(allocated_ptr);
  InitMask(stream_exec_,
           static_cast<char*>(allocated_ptr) + req_size - MASK_BYTES,
           after_mask);
  return rv;
}
void GPUDebugAllocator::DeallocateRaw(void* ptr) {
  if (ptr != nullptr) {
    CHECK(CheckHeader(ptr)) << "before_mask has been overwritten";
    CHECK(CheckFooter(ptr)) << "after_mask has been overwritten";

    // Backtrack to the beginning of the header.
    ptr = static_cast<void*>(static_cast<char*>(ptr) - MASK_BYTES);
  }
  // Deallocate the memory
  base_allocator_->DeallocateRaw(ptr);
}

bool GPUDebugAllocator::TracksAllocationSizes() { return true; }

size_t GPUDebugAllocator::RequestedSize(const void* ptr) {
  auto req_size = base_allocator_->RequestedSize(static_cast<const char*>(ptr) -
                                                 MASK_BYTES);
  return req_size - 2 * MASK_BYTES;
}

size_t GPUDebugAllocator::AllocatedSize(const void* ptr) {
  return base_allocator_->AllocatedSize(static_cast<const char*>(ptr) -
                                        MASK_BYTES);
}

int64 GPUDebugAllocator::AllocationId(const void* ptr) {
  return base_allocator_->AllocationId(static_cast<const char*>(ptr) -
                                       MASK_BYTES);
}

void GPUDebugAllocator::GetStats(AllocatorStats* stats) {
  base_allocator_->GetStats(stats);
}

void GPUDebugAllocator::ClearStats() { base_allocator_->ClearStats(); }

bool GPUDebugAllocator::CheckHeader(void* ptr) {
  return CheckMask(stream_exec_, static_cast<char*>(ptr) - MASK_BYTES,
                   before_mask);
}

bool GPUDebugAllocator::CheckFooter(void* ptr) {
  char* original_ptr = static_cast<char*>(ptr) - MASK_BYTES;
  size_t req_size = base_allocator_->RequestedSize(original_ptr);
  return CheckMask(stream_exec_, original_ptr + req_size - MASK_BYTES,
                   after_mask);
}

// -----------------------------------------------------------------------------
// GPUNanResetAllocator
// -----------------------------------------------------------------------------
GPUNanResetAllocator::GPUNanResetAllocator(Allocator* allocator,
                                           PlatformGpuId platform_gpu_id)
    : base_allocator_(allocator) {
  stream_exec_ =
      GpuIdUtil::ExecutorForPlatformGpuId(platform_gpu_id).ValueOrDie();
}

GPUNanResetAllocator::~GPUNanResetAllocator() { delete base_allocator_; }

void* GPUNanResetAllocator::AllocateRaw(size_t alignment, size_t num_bytes) {
  void* allocated_ptr = base_allocator_->AllocateRaw(alignment, num_bytes);
  if (allocated_ptr == nullptr) return allocated_ptr;

  // Initialize the buffer to Nans
  size_t req_size = base_allocator_->RequestedSize(allocated_ptr);
  std::vector<float> nans((req_size + sizeof(float) - 1) / sizeof(float),
                          std::nanf(""));
  se::DeviceMemory<float> nan_ptr{
      se::DeviceMemoryBase{static_cast<float*>(allocated_ptr), req_size}};

  if (!stream_exec_->SynchronousMemcpy(&nan_ptr, &nans[0], req_size)) {
    LOG(ERROR) << "Could not initialize to NaNs";
  }

  return allocated_ptr;
}
void GPUNanResetAllocator::DeallocateRaw(void* ptr) {
  if (ptr != nullptr) {
    // Reset the buffer to Nans
    size_t req_size = base_allocator_->RequestedSize(ptr);
    std::vector<float> nans((req_size + sizeof(float) - 1) / sizeof(float),
                            std::nanf(""));
    se::DeviceMemory<float> nan_ptr{
        se::DeviceMemoryBase{static_cast<float*>(ptr), req_size}};
    if (!stream_exec_->SynchronousMemcpy(&nan_ptr, &nans[0], req_size)) {
      LOG(ERROR) << "Could not initialize to NaNs";
    }
  }

  // Deallocate the memory
  base_allocator_->DeallocateRaw(ptr);
}

size_t GPUNanResetAllocator::RequestedSize(const void* ptr) {
  return base_allocator_->RequestedSize(ptr);
}

size_t GPUNanResetAllocator::AllocatedSize(const void* ptr) {
  return base_allocator_->AllocatedSize(ptr);
}

void GPUNanResetAllocator::GetStats(AllocatorStats* stats) {
  base_allocator_->GetStats(stats);
}

void GPUNanResetAllocator::ClearStats() { base_allocator_->ClearStats(); }

}  // namespace tensorflow
<commit_msg>SynchronousMemcpy changed to SynchronousMemcpyD2H and SynchronousMemcpyH2D<commit_after>/* Copyright 2015 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/common_runtime/gpu/gpu_debug_allocator.h"

#include <cstddef>
#include <vector>

#include "tensorflow/core/common_runtime/gpu/gpu_id.h"
#include "tensorflow/core/common_runtime/gpu/gpu_id_utils.h"
#include "tensorflow/core/common_runtime/gpu/gpu_init.h"
#include "tensorflow/core/platform/stream_executor.h"

#define MASK_WORDS 2
#define MASK_BYTES (MASK_WORDS * sizeof(int64))

namespace tensorflow {
namespace {

int64* NewMask(int64 word) {
  int64* m = new int64[MASK_WORDS];
  for (int i = 0; i < MASK_WORDS; ++i) {
    m[i] = word;
  }
  return m;
}

int64* before_mask = NewMask(0xabababababababab);
int64* after_mask = NewMask(0xcdcdcdcdcdcdcdcd);

bool CheckMask(se::StreamExecutor* exec, void* ptr, int64* mask) {
  se::DeviceMemory<int64> gpu_ptr{se::DeviceMemoryBase{ptr, MASK_BYTES}};
  int64 tmp[MASK_WORDS];

  Status result = exec->SynchronousMemcpyD2H(gpu_ptr, MASK_BYTES, tmp);
  if (!result.ok()) {
    LOG(FATAL) << "Could not copy debug mask";
  }

  bool ok = true;
  for (int i = 0; i < MASK_WORDS; ++i) {
    ok &= (mask[i] == tmp[i]);
    if (!ok) {
      LOG(ERROR) << "i=" << i
                 << " mask=" << reinterpret_cast<const void*>(mask[i])
                 << " field=" << reinterpret_cast<const void*>(tmp[i]);
    }
  }

  return ok;
}

void InitMask(se::StreamExecutor* exec, void* ptr, int64* mask) {
  se::DeviceMemory<int64> gpu_ptr{se::DeviceMemoryBase{ptr, MASK_BYTES}};
  Status result = exec->SynchronousMemcpyH2D(mask, MASK_BYTES, &gpu_ptr);
  if (!result.ok()) {
    LOG(FATAL) << "Could not copy debug mask";
  }
}

}  // namespace

// -----------------------------------------------------------------------------
// GPUDebugAllocator
// -----------------------------------------------------------------------------
GPUDebugAllocator::GPUDebugAllocator(Allocator* allocator,
                                     PlatformGpuId platform_gpu_id)
    : base_allocator_(allocator) {
  stream_exec_ =
      GpuIdUtil::ExecutorForPlatformGpuId(platform_gpu_id).ValueOrDie();
}

GPUDebugAllocator::~GPUDebugAllocator() { delete base_allocator_; }

void* GPUDebugAllocator::AllocateRaw(size_t alignment, size_t num_bytes) {
  num_bytes += (2 * MASK_BYTES);
  void* allocated_ptr = base_allocator_->AllocateRaw(alignment, num_bytes);
  if (allocated_ptr == nullptr) return allocated_ptr;

  // Return the pointer after the header
  void* rv = static_cast<char*>(allocated_ptr) + MASK_BYTES;

  // Write the header at allocated_ptr
  InitMask(stream_exec_, allocated_ptr, before_mask);

  // Write the footer at the end.
  size_t req_size = base_allocator_->RequestedSize(allocated_ptr);
  InitMask(stream_exec_,
           static_cast<char*>(allocated_ptr) + req_size - MASK_BYTES,
           after_mask);
  return rv;
}
void GPUDebugAllocator::DeallocateRaw(void* ptr) {
  if (ptr != nullptr) {
    CHECK(CheckHeader(ptr)) << "before_mask has been overwritten";
    CHECK(CheckFooter(ptr)) << "after_mask has been overwritten";

    // Backtrack to the beginning of the header.
    ptr = static_cast<void*>(static_cast<char*>(ptr) - MASK_BYTES);
  }
  // Deallocate the memory
  base_allocator_->DeallocateRaw(ptr);
}

bool GPUDebugAllocator::TracksAllocationSizes() { return true; }

size_t GPUDebugAllocator::RequestedSize(const void* ptr) {
  auto req_size = base_allocator_->RequestedSize(static_cast<const char*>(ptr) -
                                                 MASK_BYTES);
  return req_size - 2 * MASK_BYTES;
}

size_t GPUDebugAllocator::AllocatedSize(const void* ptr) {
  return base_allocator_->AllocatedSize(static_cast<const char*>(ptr) -
                                        MASK_BYTES);
}

int64 GPUDebugAllocator::AllocationId(const void* ptr) {
  return base_allocator_->AllocationId(static_cast<const char*>(ptr) -
                                       MASK_BYTES);
}

void GPUDebugAllocator::GetStats(AllocatorStats* stats) {
  base_allocator_->GetStats(stats);
}

void GPUDebugAllocator::ClearStats() { base_allocator_->ClearStats(); }

bool GPUDebugAllocator::CheckHeader(void* ptr) {
  return CheckMask(stream_exec_, static_cast<char*>(ptr) - MASK_BYTES,
                   before_mask);
}

bool GPUDebugAllocator::CheckFooter(void* ptr) {
  char* original_ptr = static_cast<char*>(ptr) - MASK_BYTES;
  size_t req_size = base_allocator_->RequestedSize(original_ptr);
  return CheckMask(stream_exec_, original_ptr + req_size - MASK_BYTES,
                   after_mask);
}

// -----------------------------------------------------------------------------
// GPUNanResetAllocator
// -----------------------------------------------------------------------------
GPUNanResetAllocator::GPUNanResetAllocator(Allocator* allocator,
                                           PlatformGpuId platform_gpu_id)
    : base_allocator_(allocator) {
  stream_exec_ =
      GpuIdUtil::ExecutorForPlatformGpuId(platform_gpu_id).ValueOrDie();
}

GPUNanResetAllocator::~GPUNanResetAllocator() { delete base_allocator_; }

void* GPUNanResetAllocator::AllocateRaw(size_t alignment, size_t num_bytes) {
  void* allocated_ptr = base_allocator_->AllocateRaw(alignment, num_bytes);
  if (allocated_ptr == nullptr) return allocated_ptr;

  // Initialize the buffer to Nans
  size_t req_size = base_allocator_->RequestedSize(allocated_ptr);
  std::vector<float> nans((req_size + sizeof(float) - 1) / sizeof(float),
                          std::nanf(""));
  se::DeviceMemory<float> nan_ptr{
      se::DeviceMemoryBase{static_cast<float*>(allocated_ptr), req_size}};

  Status result = stream_exec_->SynchronousMemcpyH2D(&nans[0], req_size,
                                                     &nan_ptr);
  if (!result.ok()) {
    LOG(ERROR) << "Could not initialize to NaNs";
  }

  return allocated_ptr;
}
void GPUNanResetAllocator::DeallocateRaw(void* ptr) {
  if (ptr != nullptr) {
    // Reset the buffer to Nans
    size_t req_size = base_allocator_->RequestedSize(ptr);
    std::vector<float> nans((req_size + sizeof(float) - 1) / sizeof(float),
                            std::nanf(""));
    se::DeviceMemory<float> nan_ptr{
        se::DeviceMemoryBase{static_cast<float*>(ptr), req_size}};
    Status result = stream_exec_->SynchronousMemcpyH2D(&nans[0], req_size,
                                                       &nan_ptr);
    if (!result.ok()) {
      LOG(ERROR) << "Could not initialize to NaNs";
    }
  }

  // Deallocate the memory
  base_allocator_->DeallocateRaw(ptr);
}

size_t GPUNanResetAllocator::RequestedSize(const void* ptr) {
  return base_allocator_->RequestedSize(ptr);
}

size_t GPUNanResetAllocator::AllocatedSize(const void* ptr) {
  return base_allocator_->AllocatedSize(ptr);
}

void GPUNanResetAllocator::GetStats(AllocatorStats* stats) {
  base_allocator_->GetStats(stats);
}

void GPUNanResetAllocator::ClearStats() { base_allocator_->ClearStats(); }

}  // namespace tensorflow
<|endoftext|>


<commit_before>/* Copyright 2021 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 <string>

#include "tensorflow/core/framework/common_shape_fns.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/resource_mgr.h"
#include "tensorflow/core/framework/shape_inference.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/tstring.h"
#include "tensorflow/lite/c/c_api_types.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/core/subgraph.h"
#include "tensorflow/lite/delegates/flex/buffer_map_util.h"
#include "tensorflow/lite/delegates/flex/subgraph_resource.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/string_util.h"

namespace tensorflow {

namespace {
constexpr int kTfLiteSubgraphResource = 0;
}

REGISTER_OP("TfLiteSubgraphExecute")
    .Input("subgraph_key: string")
    .Input("args: Tin")
    .Output("output: Tout")
    .Attr("Tin: list(type) >= 0")
    .Attr("Tout: list(type) >= 0")
    .SetShapeFn(shape_inference::UnknownShape);

// The `TfLiteSubgraphExecute` executes a tflite subgraph with the designated
// inputs. This op will first look up the tflite subgraph from TF resource
// manager based on the resource name stored on the first input, and then it
// will call that specific subgraph with the remaining arguments. The first
// input of this op is always a scalar string, which denotes the name of the
// subgraph resource. The remaining inputs will be fed to the subgraph as
// inputs, so the caller needs to ensure that the remaining inputs match with
// the subgraph's expected inputs. This is currently WIP/experimental and
// subject to change.
class TfLiteSubgraphExecute : public OpKernel {
 public:
  explicit TfLiteSubgraphExecute(OpKernelConstruction* ctx) : OpKernel(ctx) {}

  void Compute(OpKernelContext* ctx) override {
    // Fetch the TF Lite subgraph to execute.
    tflite::flex::TFLiteSubgraphResource* resource = nullptr;
    OP_REQUIRES_OK(
        ctx,
        ctx->resource_manager()->Lookup<tflite::flex::TFLiteSubgraphResource>(
            "flex", ctx->input(kTfLiteSubgraphResource).flat<tstring>()(0),
            &resource));
    tensorflow::core::ScopedUnref unref_resource(resource);

    // Try to acquire a mutex lock from this resource. This is because tflite
    // subgraph is not thread-safe and we need to guarantee exclusive access to
    // it.
    mutex_lock lock(resource->GetExclusiveLock());
    tflite::Subgraph& subgraph_selected = resource->GetSubgraphResource();

    OP_REQUIRES(ctx, ctx->num_inputs() == subgraph_selected.inputs().size() + 1,
                errors::InvalidArgument("TF Lite subgraph expects ",
                                        subgraph_selected.inputs().size(),
                                        " inputs, but received ",
                                        ctx->num_inputs() - 1, "."));

    // Resize input tensors if necessary.
    ResizeInputTensor(ctx, subgraph_selected);

    subgraph_selected.AllocateTensors();

    // Copy input tensors to subgraph.
    SetSubgraphInput(ctx, subgraph_selected);

    OP_REQUIRES(ctx, subgraph_selected.Invoke() == kTfLiteOk,
                errors::Internal("Failed to invoke tflite subgraph"));

    // Copy tflite results.
    CopyTFLiteSubgraphResult(ctx, subgraph_selected);
  }

 private:
  void ResizeInputTensor(OpKernelContext* ctx,
                         tflite::Subgraph& subgraph_selected) const {
    for (int i = 0; i < subgraph_selected.inputs().size(); ++i) {
      // Shift index by 1 since the first input is always the resource name.
      const Tensor& tf_tensor = ctx->input(i + 1);
      TfLiteTensor* subgraph_input =
          subgraph_selected.tensor(subgraph_selected.inputs()[i]);

      bool need_resize = false;
      for (int dim = 0; dim < tf_tensor.shape().dims(); dim++) {
        if (tf_tensor.shape().dim_size(dim) !=
            subgraph_input->dims->data[dim]) {
          need_resize = true;
          break;
        }
      }
      if (need_resize) {
        std::vector<int> new_shape;
        for (auto dim : tf_tensor.shape().dim_sizes()) {
          new_shape.push_back(dim);
        }
        OP_REQUIRES(ctx,
                    subgraph_selected.ResizeInputTensor(
                        subgraph_selected.inputs()[i], new_shape) == kTfLiteOk,
                    errors::Internal("Failed to resize tflite tensor"));
      }
    }
  }

  void SetSubgraphInput(OpKernelContext* ctx,
                        tflite::Subgraph& subgraph_selected) const {
    for (int i = 0; i < subgraph_selected.inputs().size(); ++i) {
      const Tensor& tf_tensor = ctx->input(i + 1);
      TfLiteTensor* subgraph_input =
          subgraph_selected.tensor(subgraph_selected.inputs()[i]);

      if (subgraph_input->type == kTfLiteString) {
        OP_REQUIRES(ctx, tf_tensor.dtype() == tensorflow::DT_STRING,
                    errors::InvalidArgument("Tensor doesn't have string type"));
        tflite::DynamicBuffer dynamic_buffer;
        auto tf_data = tf_tensor.flat<tensorflow::tstring>();
        for (int i = 0; i < tf_tensor.NumElements(); ++i) {
          dynamic_buffer.AddString(tf_data(i).data(), tf_data(i).size());
        }

        dynamic_buffer.WriteToTensor(subgraph_input, /*new_shape=*/nullptr);
      } else if (subgraph_input->type == kTfLiteResource ||
                 subgraph_input->type == kTfLiteVariant) {
        // TODO(b/179094265): This is an experimental implementation, subject to
        // change. This can be re-implemented with life cycle management
        // mechanism like reference counting.
        const size_t required_bytes = sizeof(tensorflow::Tensor**);
        const tensorflow::Tensor** tf_tensor_ptr =
            reinterpret_cast<const tensorflow::Tensor**>(
                malloc(required_bytes));
        *tf_tensor_ptr = &tf_tensor;

        TfLiteTensorDataFree(subgraph_input);
        subgraph_input->data.raw = reinterpret_cast<char*>(tf_tensor_ptr);
        subgraph_input->bytes = required_bytes;
        subgraph_input->data_is_stale = true;
      } else {
        tensorflow::StringPiece tensor_data = tf_tensor.tensor_data();
        OP_REQUIRES(ctx, subgraph_input->bytes == tensor_data.size(),
                    errors::Internal("tensor size doesn't match"));
        // TODO(b/181352924): This could incur some overhead in memory copy.
        // Optimize this away in the future.
        memcpy(subgraph_input->data.raw, tensor_data.data(),
               tensor_data.size());
      }
    }
  }

  void CopyTFLiteSubgraphResult(OpKernelContext* ctx,
                                tflite::Subgraph& subgraph_selected) const {
    for (int i = 0; i < subgraph_selected.outputs().size(); ++i) {
      OP_REQUIRES(ctx,
                  subgraph_selected.EnsureTensorDataIsReadable(
                      subgraph_selected.outputs()[i]) == kTfLiteOk,
                  errors::Internal("TF lite subgraph output is not readable"));
      // Create an output tensor.
      TfLiteTensor* subgraph_output =
          subgraph_selected.tensor(subgraph_selected.outputs()[i]);

      Tensor tensor;
      OP_REQUIRES_OK(
          ctx, tflite::flex::SetTfTensorFromTfLite(subgraph_output, &tensor));
      ctx->set_output(i, std::move(tensor));
    }
  }
};

REGISTER_KERNEL_BUILDER(Name("TfLiteSubgraphExecute").Device(DEVICE_CPU),
                        TfLiteSubgraphExecute);

}  // namespace tensorflow
<commit_msg>TfLiteSubgraphExecute: Optimize calling subgraph_selected.AllocateTensors()<commit_after>/* Copyright 2021 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 <string>

#include "tensorflow/core/framework/common_shape_fns.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/framework/resource_mgr.h"
#include "tensorflow/core/framework/shape_inference.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/tstring.h"
#include "tensorflow/lite/c/c_api_types.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/core/subgraph.h"
#include "tensorflow/lite/delegates/flex/buffer_map_util.h"
#include "tensorflow/lite/delegates/flex/subgraph_resource.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/string_util.h"

namespace tensorflow {

namespace {
constexpr int kTfLiteSubgraphResource = 0;
}

REGISTER_OP("TfLiteSubgraphExecute")
    .Input("subgraph_key: string")
    .Input("args: Tin")
    .Output("output: Tout")
    .Attr("Tin: list(type) >= 0")
    .Attr("Tout: list(type) >= 0")
    .SetShapeFn(shape_inference::UnknownShape);

// The `TfLiteSubgraphExecute` executes a tflite subgraph with the designated
// inputs. This op will first look up the tflite subgraph from TF resource
// manager based on the resource name stored on the first input, and then it
// will call that specific subgraph with the remaining arguments. The first
// input of this op is always a scalar string, which denotes the name of the
// subgraph resource. The remaining inputs will be fed to the subgraph as
// inputs, so the caller needs to ensure that the remaining inputs match with
// the subgraph's expected inputs. This is currently WIP/experimental and
// subject to change.
class TfLiteSubgraphExecute : public OpKernel {
 public:
  explicit TfLiteSubgraphExecute(OpKernelConstruction* ctx)
      : OpKernel(ctx), tfl_tensors_need_allocation_(true) {}

  void Compute(OpKernelContext* ctx) override {
    // Fetch the TF Lite subgraph to execute.
    tflite::flex::TFLiteSubgraphResource* resource = nullptr;
    OP_REQUIRES_OK(
        ctx,
        ctx->resource_manager()->Lookup<tflite::flex::TFLiteSubgraphResource>(
            "flex", ctx->input(kTfLiteSubgraphResource).flat<tstring>()(0),
            &resource));
    tensorflow::core::ScopedUnref unref_resource(resource);

    // Try to acquire a mutex lock from this resource. This is because tflite
    // subgraph is not thread-safe and we need to guarantee exclusive access to
    // it.
    mutex_lock lock(resource->GetExclusiveLock());
    tflite::Subgraph& subgraph_selected = resource->GetSubgraphResource();

    OP_REQUIRES(ctx, ctx->num_inputs() == subgraph_selected.inputs().size() + 1,
                errors::InvalidArgument("TF Lite subgraph expects ",
                                        subgraph_selected.inputs().size(),
                                        " inputs, but received ",
                                        ctx->num_inputs() - 1, "."));

    // Resize input tensors if necessary.
    ResizeInputTensor(ctx, subgraph_selected);

    if (tfl_tensors_need_allocation_) {
      subgraph_selected.AllocateTensors();
      tfl_tensors_need_allocation_ = false;
    }

    // Copy input tensors to subgraph.
    SetSubgraphInput(ctx, subgraph_selected);

    OP_REQUIRES(ctx, subgraph_selected.Invoke() == kTfLiteOk,
                errors::Internal("Failed to invoke tflite subgraph"));

    // Copy tflite results.
    CopyTFLiteSubgraphResult(ctx, subgraph_selected);
  }

 private:
  void ResizeInputTensor(OpKernelContext* ctx,
                         tflite::Subgraph& subgraph_selected) {
    for (int i = 0; i < subgraph_selected.inputs().size(); ++i) {
      // Shift index by 1 since the first input is always the resource name.
      const Tensor& tf_tensor = ctx->input(i + 1);
      TfLiteTensor* subgraph_input =
          subgraph_selected.tensor(subgraph_selected.inputs()[i]);

      bool need_resize = false;
      for (int dim = 0; dim < tf_tensor.shape().dims(); dim++) {
        if (tf_tensor.shape().dim_size(dim) !=
            subgraph_input->dims->data[dim]) {
          need_resize = true;
          break;
        }
      }
      if (need_resize) {
        std::vector<int> new_shape;
        for (auto dim : tf_tensor.shape().dim_sizes()) {
          new_shape.push_back(dim);
        }
        tfl_tensors_need_allocation_ = true;
        OP_REQUIRES(ctx,
                    subgraph_selected.ResizeInputTensor(
                        subgraph_selected.inputs()[i], new_shape) == kTfLiteOk,
                    errors::Internal("Failed to resize tflite tensor"));
      }
    }
  }

  void SetSubgraphInput(OpKernelContext* ctx,
                        tflite::Subgraph& subgraph_selected) const {
    for (int i = 0; i < subgraph_selected.inputs().size(); ++i) {
      const Tensor& tf_tensor = ctx->input(i + 1);
      TfLiteTensor* subgraph_input =
          subgraph_selected.tensor(subgraph_selected.inputs()[i]);

      if (subgraph_input->type == kTfLiteString) {
        OP_REQUIRES(ctx, tf_tensor.dtype() == tensorflow::DT_STRING,
                    errors::InvalidArgument("Tensor doesn't have string type"));
        tflite::DynamicBuffer dynamic_buffer;
        auto tf_data = tf_tensor.flat<tensorflow::tstring>();
        for (int i = 0; i < tf_tensor.NumElements(); ++i) {
          dynamic_buffer.AddString(tf_data(i).data(), tf_data(i).size());
        }

        dynamic_buffer.WriteToTensor(subgraph_input, /*new_shape=*/nullptr);
      } else if (subgraph_input->type == kTfLiteResource ||
                 subgraph_input->type == kTfLiteVariant) {
        // TODO(b/179094265): This is an experimental implementation, subject to
        // change. This can be re-implemented with life cycle management
        // mechanism like reference counting.
        const size_t required_bytes = sizeof(tensorflow::Tensor**);
        const tensorflow::Tensor** tf_tensor_ptr =
            reinterpret_cast<const tensorflow::Tensor**>(
                malloc(required_bytes));
        *tf_tensor_ptr = &tf_tensor;

        TfLiteTensorDataFree(subgraph_input);
        subgraph_input->data.raw = reinterpret_cast<char*>(tf_tensor_ptr);
        subgraph_input->bytes = required_bytes;
        subgraph_input->data_is_stale = true;
      } else {
        tensorflow::StringPiece tensor_data = tf_tensor.tensor_data();
        OP_REQUIRES(ctx, subgraph_input->bytes == tensor_data.size(),
                    errors::Internal("tensor size doesn't match"));
        // TODO(b/181352924): This could incur some overhead in memory copy.
        // Optimize this away in the future.
        memcpy(subgraph_input->data.raw, tensor_data.data(),
               tensor_data.size());
      }
    }
  }

  void CopyTFLiteSubgraphResult(OpKernelContext* ctx,
                                tflite::Subgraph& subgraph_selected) const {
    for (int i = 0; i < subgraph_selected.outputs().size(); ++i) {
      OP_REQUIRES(ctx,
                  subgraph_selected.EnsureTensorDataIsReadable(
                      subgraph_selected.outputs()[i]) == kTfLiteOk,
                  errors::Internal("TF lite subgraph output is not readable"));
      // Create an output tensor.
      TfLiteTensor* subgraph_output =
          subgraph_selected.tensor(subgraph_selected.outputs()[i]);

      Tensor tensor;
      OP_REQUIRES_OK(
          ctx, tflite::flex::SetTfTensorFromTfLite(subgraph_output, &tensor));
      ctx->set_output(i, std::move(tensor));
    }
  }

  // Tells if the target subgraph needs to invoko AllocateTensors().
  bool tfl_tensors_need_allocation_;
};

REGISTER_KERNEL_BUILDER(Name("TfLiteSubgraphExecute").Device(DEVICE_CPU),
                        TfLiteSubgraphExecute);

}  // namespace tensorflow
<|endoftext|>