"vscode:/vscode.git/clone" did not exist on "5502bac28a87774940ee65f816eda66a26cbbb09"
Commit 029b1e64 authored by mei-ye's avatar mei-ye
Browse files

merge to master

parent 733591e1
...@@ -18,7 +18,7 @@ else() ...@@ -18,7 +18,7 @@ else()
set(MIGRAPH_ENABLE_GPU Off CACHE BOOL "") set(MIGRAPH_ENABLE_GPU Off CACHE BOOL "")
endif() endif()
add_compile_options(-std=c++14) add_compile_options(-std=c++14 -g -O0)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(EnableCompilerWarnings) include(EnableCompilerWarnings)
......
...@@ -10,6 +10,8 @@ add_library(migraph ...@@ -10,6 +10,8 @@ add_library(migraph
program.cpp program.cpp
shape.cpp shape.cpp
simplify_reshapes.cpp simplify_reshapes.cpp
opt/memory_coloring.cpp
opt/memory_coloring_impl.cpp
) )
rocm_clang_tidy_check(migraph) rocm_clang_tidy_check(migraph)
target_include_directories(migraph PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>) target_include_directories(migraph PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
...@@ -19,3 +21,10 @@ add_subdirectory(targets/cpu) ...@@ -19,3 +21,10 @@ add_subdirectory(targets/cpu)
if(MIGRAPH_ENABLE_GPU) if(MIGRAPH_ENABLE_GPU)
add_subdirectory(targets/gpu) add_subdirectory(targets/gpu)
endif() endif()
install (TARGETS migraph
LIBRARY DESTINATION /opt/rocm/lib)
install (DIRECTORY include/migraph DESTINATION /opt/rocm/include)
...@@ -4,12 +4,17 @@ ...@@ -4,12 +4,17 @@
#include <migraph/operators.hpp> #include <migraph/operators.hpp>
#include <migraph/iterator_for.hpp> #include <migraph/iterator_for.hpp>
#include <migraph/ranges.hpp> #include <migraph/ranges.hpp>
#include <migraph/stringutils.hpp>
#include <migraph/pass_config.hpp>
namespace migraph { namespace migraph {
void eliminate_allocation::apply(program& p) const void eliminate_allocation::apply(program& p) const
{ {
assert(alignment > 0); assert(alignment > 0);
if (!enabled(MIGRAPH_DISABLE_MEMORY_COLORING{}))
return;
std::size_t n = 0; std::size_t n = 0;
std::vector<std::pair<instruction_ref, std::size_t>> allocs; std::vector<std::pair<instruction_ref, std::size_t>> allocs;
for(auto ins : iterator_for(p)) for(auto ins : iterator_for(p))
......
...@@ -538,7 +538,7 @@ struct load ...@@ -538,7 +538,7 @@ struct load
{ {
shape s; shape s;
std::size_t offset = 0; std::size_t offset = 0;
std::string name() const { return "load"; } std::string name() const { return "load:"; }
shape compute_shape(const std::vector<shape>& inputs) const shape compute_shape(const std::vector<shape>& inputs) const
{ {
check_shapes{inputs}.has(1); check_shapes{inputs}.has(1);
...@@ -548,6 +548,18 @@ struct load ...@@ -548,6 +548,18 @@ struct load
{ {
return {s, args[0].data() + offset}; return {s, args[0].data() + offset};
} }
};
struct write_literal
{
std::size_t offset = 0;
bool pre_copy = false;
std::string name() const { return "write_literal"; }
shape compute_shape(std::vector<shape> inputs) const { return inputs.at(1); }
argument compute(context&, const shape&, const std::vector<argument>&) const
{
MIGRAPH_THROW("not computable");
}
}; };
struct outline struct outline
......
...@@ -216,6 +216,7 @@ inline const ValueType& any_cast(const pass& x) ...@@ -216,6 +216,7 @@ inline const ValueType& any_cast(const pass& x)
#endif #endif
} // namespace migraph } // namespace migraph
#endif #endif
...@@ -18,7 +18,9 @@ struct program_impl; ...@@ -18,7 +18,9 @@ struct program_impl;
const operation& get_operation(instruction_ref ins); const operation& get_operation(instruction_ref ins);
/**
/**
* @brief Stores the instruction stream * @brief Stores the instruction stream
*/ */
struct program struct program
...@@ -28,7 +30,7 @@ struct program ...@@ -28,7 +30,7 @@ struct program
program& operator=(program&&) noexcept; program& operator=(program&&) noexcept;
~program() noexcept; ~program() noexcept;
using parameter_map = std::unordered_map<std::string, argument>; using parameter_map = migraph::parameter_map;
template <class... Ts> template <class... Ts>
instruction_ref add_instruction(operation op, Ts... args) instruction_ref add_instruction(operation op, Ts... args)
...@@ -75,6 +77,8 @@ struct program ...@@ -75,6 +77,8 @@ struct program
shape get_parameter_shape(std::string name) const; shape get_parameter_shape(std::string name) const;
instruction_ref get_parameter(std::string name) const;
std::unordered_map<std::string, shape> get_parameter_shapes() const; std::unordered_map<std::string, shape> get_parameter_shapes() const;
argument eval(parameter_map params) const; argument eval(parameter_map params) const;
...@@ -89,7 +93,7 @@ struct program ...@@ -89,7 +93,7 @@ struct program
instruction_ref validate() const; instruction_ref validate() const;
void compile(const target& t, tracer trace = tracer{}); void compile(const target& t, tracer trace = tracer{}, parameter_map params = parameter_map());
void perf_report(std::ostream& os, std::size_t n, parameter_map params) const; void perf_report(std::ostream& os, std::size_t n, parameter_map params) const;
......
...@@ -8,13 +8,16 @@ ...@@ -8,13 +8,16 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <unordered_map>
#include <migraph/context.hpp> #include <migraph/context.hpp>
#include <migraph/pass.hpp> #include <migraph/pass.hpp>
#include <migraph/argument.hpp>
namespace migraph { namespace migraph {
using parameter_map = std::unordered_map<std::string, argument>;
#ifdef DOXYGEN #ifdef DOXYGEN
/// An interface for a compilation target /// An interface for a compilation target
struct target struct target
{ {
...@@ -33,7 +36,7 @@ struct target ...@@ -33,7 +36,7 @@ struct target
* @brief Construct a context for the target. * @brief Construct a context for the target.
* @return The context to be used during compilation and execution. * @return The context to be used during compilation and execution.
*/ */
context get_context() const; context get_context(parameter_map params = parameter_map()) const;
}; };
#else #else
...@@ -119,10 +122,10 @@ struct target ...@@ -119,10 +122,10 @@ struct target
return (*this).private_detail_te_get_handle().get_passes(ctx); return (*this).private_detail_te_get_handle().get_passes(ctx);
} }
context get_context() const context get_context(parameter_map params = parameter_map()) const
{ {
assert((*this).private_detail_te_handle_mem_var); assert((*this).private_detail_te_handle_mem_var);
return (*this).private_detail_te_get_handle().get_context(); return (*this).private_detail_te_get_handle().get_context(params);
} }
private: private:
...@@ -134,7 +137,7 @@ struct target ...@@ -134,7 +137,7 @@ struct target
virtual std::string name() const = 0; virtual std::string name() const = 0;
virtual std::vector<pass> get_passes(context& ctx) const = 0; virtual std::vector<pass> get_passes(context& ctx) const = 0;
virtual context get_context() const = 0; virtual context get_context(parameter_map params = parameter_map()) const = 0;
}; };
template <typename PrivateDetailTypeErasedT> template <typename PrivateDetailTypeErasedT>
...@@ -173,7 +176,7 @@ struct target ...@@ -173,7 +176,7 @@ struct target
return private_detail_te_value.get_passes(ctx); return private_detail_te_value.get_passes(ctx);
} }
context get_context() const override { return private_detail_te_value.get_context(); } context get_context(parameter_map params = parameter_map()) const override { return private_detail_te_value.get_context(params); }
PrivateDetailTypeErasedT private_detail_te_value; PrivateDetailTypeErasedT private_detail_te_value;
}; };
......
#ifndef MIGRAPH_GUARD_RTGLIB_COMMON_HEADER_HPP
#define MIGRAPH_GUARD_RTGLIB_COMMON_HEADER_HPP
#include <migraph/program.hpp>
#include <migraph/stringutils.hpp>
#include <migraph/instruction.hpp>
#include <migraph/operators.hpp>
#include <migraph/iterator_for.hpp>
#include <migraph/pass_config.hpp>
#include <set>
#include <list>
#include <vector>
#include <queue>
namespace migraph {
#define MIGRAPH_DEBUG_OPT
#ifdef MIGRAPH_DEBUG_OPT
#define MIGRAPH_DEBUG(s) s
#else
#define MIGRAPH_DEBUG(s)
#endif // MIGRAPH_DEBUG_OPT
} // namespace migraph
#endif // MIGRAPH_GUARD_RTGLIB_COMMON_HEADER_HPP
#include <migraph/memory_coloring.hpp>
#include "memory_coloring_impl.hpp"
namespace migraph {
void memory_coloring::apply(program& p) const
{
if (!enabled(MIGRAPH_DISABLE_MEMORY_COLORING{})) {
memory_coloring_impl opt(&p);
opt.run();
}
}
} // namespace migraph
#include "memory_coloring_impl.hpp"
namespace migraph {
void memory_coloring_impl::run()
{
MIGRAPH_DEBUG(dump("---Before memory coloring---"));
MIGRAPH_DEBUG(dump_program());
register_operand_alias();
build();
if(num_of_lives != 0)
{
MIGRAPH_DEBUG(dump_intervals());
// Coloring
while(!alloc_queue.empty())
{
interval_ptr interval = alloc_queue.top();
allocate(interval);
alloc_queue.pop();
}
rewrite();
MIGRAPH_DEBUG(verify());
}
}
bool memory_coloring_impl::allocate(interval_ptr interval)
{
shape s = interval->result;
std::size_t size = s.bytes();
if(size == 0)
return false;
std::size_t element_size = size / s.elements();
live_range& segment = interval->segment;
int vn = segment.vn;
std::priority_queue<live_range*, std::vector<live_range*>, ordering> conflict_queue;
std::unordered_map<long long, live_range*> offset2_live;
offset2_live.clear();
if(conflict_table.find(vn) != conflict_table.end())
{
std::set<int>& vn_set = conflict_table[vn];
for(auto& iter : vn_set)
{
live_range* range = live_ranges[iter];
long long offset = range->offset;
if(offset != InvalidOffset)
{
conflict_queue.push(range);
if(offset2_live.find(offset) == offset2_live.end())
{
offset2_live[offset] = range;
}
else
{
live_range* prev = offset2_live[offset];
assert(prev->offset == offset);
if(prev->size < range->size)
offset2_live[offset] = range;
}
}
}
}
long long offset = 0;
while(!conflict_queue.empty())
{
live_range* range = conflict_queue.top();
long long iter_offset = range->offset;
if (offset > iter_offset) {
offset = std::max(offset, iter_offset + range->size);
} else if (offset2_live[iter_offset] == range)
{
if((iter_offset > offset) && (iter_offset - offset) >= size)
{
break;
}
offset = iter_offset + range->size;
}
// alignment
if((offset % element_size) != 0)
offset += (element_size - (offset % element_size));
conflict_queue.pop();
}
segment.offset = offset;
MIGRAPH_DEBUG(segment.dump());
required_bytes = std::max(required_bytes, offset + segment.size);
return true;
}
void memory_coloring_impl::build()
{
std::size_t num_of_instrs = p_program->size();
if(num_of_instrs == 0)
return;
int cur_points = num_of_instrs * 2;
instruction_ref iter = std::prev(p_program->end());
instruction_ref begin = p_program->begin();
std::vector<instruction_ref> dead_instrs;
std::set<int> live_set;
// Build live intervals.
live_intervals.resize(num_of_instrs);
do
{
const instruction* p_iter = &(*iter);
interval_ptr def_interval = nullptr;
bool is_dead = false;
if(instr2_live.find(p_iter) != instr2_live.end())
{
def_interval = instr2_live[p_iter];
bool is_lit = is_literal(iter);
if(is_allocate(iter) || is_lit)
{
live_range& range = def_interval->segment;
def_interval->result = iter->result;
def_interval->is_literal = is_lit;
alloc_queue.push(def_interval);
range.begin = cur_points;
def_interval->def_point = cur_points;
range.size = (iter->result).bytes();
live_set.erase(range.vn);
}
}
else if(!is_param(iter) && !is_outline(iter) && !is_check_context(iter))
{
is_dead = true;
}
int tie_ndx = get_input_tie_ndx(iter);
int cnt = -1;
for(auto&& arg : iter->arguments)
{
cnt++;
if(is_param(arg) || is_outline(arg))
{
if(is_output_param(arg))
is_dead = false;
if (def_interval != nullptr) {
def_interval->is_live_on_entry = true;
}
continue;
}
const instruction* p_arg = &(*arg);
if(cnt == tie_ndx)
{
// input memory is used as this instruction's output.
// def is considered as use. Coalesce the live intervals.
assert(def_interval != nullptr);
def_interval->add_use(cur_points);
instr2_live[p_arg] = def_interval;
}
else if(instr2_live.find(p_arg) == instr2_live.end())
{
// First time see a use, create a live interval.
int id = num_of_lives++;
interval_ptr interval = &(live_intervals[id]);
interval->id = id;
interval->segment.end = cur_points;
interval->segment.vn = ++max_value_number;
interval->add_use(cur_points);
instr2_live[p_arg] = interval;
add_conflicts(live_set, max_value_number);
live_set.insert(max_value_number);
live_ranges[max_value_number] = &(interval->segment);
earliest_end_point = cur_points;
}
else
{
interval_ptr interval = instr2_live[p_arg];
interval->add_use(cur_points);
assert(live_set.find(interval->id) != live_set.end());
}
}
if(is_dead)
dead_instrs.push_back(iter);
cur_points -= 2;
iter = std::prev(iter);
} while(iter != begin);
}
void memory_coloring_impl::register_operand_alias()
{
operand_alias["hip::allocate"] = -1;
operand_alias["@outline"] = -1;
operand_alias["check_context"] = -1;
operand_alias["@literal"] = -1;
operand_alias["@param"] = -1;
operand_alias["transpose"] = 0;
operand_alias["flatten"] = 0;
operand_alias["broadcast"] = 1;
operand_alias["reshape"] = 0;
}
void memory_coloring_impl::rewrite()
{
instruction_ref end = p_program->end();
instruction_ref scratch_param = end;
std::vector<std::size_t> dims;
dims.push_back(required_bytes / sizeof(float));
shape s = {shape::float_type, dims};
scratch_param = p_program->add_parameter("scratch", s);
for(auto ins : iterator_for(*p_program))
{
const instruction* p_iter = &(*ins);
if(instr2_live.find(p_iter) != instr2_live.end())
{
interval_ptr interval = instr2_live[p_iter];
if (interval->get_begin() == InvalidOffset)
continue;
std::size_t offset = 0;
if(interval->get_offset() == InvalidOffset)
{
assert(interval->result.bytes() == 0);
} else {
offset = interval->get_offset();
}
if(is_allocate(ins))
{
p_program->replace_instruction(
ins, load{ins->arguments.at(0)->result, offset}, scratch_param);
}
else if(is_literal(ins))
{
auto pre = p_program->add_literal(ins->lit);
bool pre_copy = (interval->get_begin() < earliest_end_point) ? true : false;
p_program->replace_instruction(ins, write_literal{offset, pre_copy}, scratch_param, pre);
}
}
}
MIGRAPH_DEBUG(dump("---After rewrite---"));
MIGRAPH_DEBUG(dump_program());
}
#ifdef MIGRAPH_DEBUG_OPT
// map liveness tracking point to instruction enum.
#define GET_INS_ENUM(x) (((x) > 0) ? (((x) >> 1) - 1) : InvalidOffset)
void memory_coloring_impl::dump(const std::string str) { std::cout << str << std::endl; }
void memory_coloring_impl::dump_program() { std::cout << *p_program << std::endl; }
void memory_coloring_impl::dump_intervals()
{
if(num_of_lives > 0)
{
std::cout << "---live intervals ---" << std::endl;
for(int i = 0; i < num_of_lives; ++i)
{
live_interval& interval = live_intervals[i];
interval.dump();
}
std::cout << "---conflict table---" << std::endl;
for(int i = 0; i <= max_value_number; ++i)
{
std::cout << " segment:" << i;
std::cout << " =>";
std::set<int>& table = conflict_table[i];
for(auto& iter : table)
{
std::cout << (iter) << ",";
}
}
std::cout << std::endl;
}
}
void memory_coloring_impl::verify()
{
if(num_of_lives > 0)
{
for(int i = 0; i < num_of_lives; ++i)
{
live_interval& interval = live_intervals[i];
live_range& segment = interval.segment;
if (segment.begin == InvalidOffset) {
assert(interval.is_live_on_entry);
continue;
}
if(segment.offset == InvalidOffset) {
continue;
}
int vn = segment.vn;
if(conflict_table.find(vn) != conflict_table.end())
{
std::set<int>& vn_set = conflict_table[vn];
for(auto& iter : vn_set)
{
live_range* range = live_ranges[iter];
if(range->offset == InvalidOffset)
continue;
if(!is_disjoin(*range, segment))
assert(false);
}
}
}
}
}
void live_range::dump()
{
std::cout << " segment:" << vn;
std::cout << " [" << GET_INS_ENUM(begin) << ", " << GET_INS_ENUM(end) << "]";
if(offset != InvalidOffset)
{
std::cout << " mem:";
std::cout << " [" << offset << "," << offset + size - 1 << "]";
}
std::cout << std::endl;
}
void live_interval::dump()
{
std::cout << "id:" << id;
segment.dump();
std::cout << " uses:";
for(auto& iter : use_points)
{
std::cout << " " << GET_INS_ENUM(iter) << ",";
}
std::cout << " def:";
std::cout << " " << GET_INS_ENUM(def_point);
if(is_literal)
std::cout << " literal";
std::cout << " " << result;
std::cout << std::endl;
}
#endif
} // namespace migraph
#ifndef MIGRAPH_GUARD_RTGLIB_MEMORY_COLORING_IMPL_HPP
#define MIGRAPH_GUARD_RTGLIB_MEMORY_COLORING_IMPL_HPP
#include "common_header.hpp"
namespace migraph {
static const int InvalidOffset = -1;
struct live_range
{
int begin; // begin point in the instruction stream.
int end; // end point in the instruction stream.
long long offset; // offset to base pointer of allocated memory trunk.
int vn; // value number that identifies this live_range.
long long size; // size of required memory in bytes
#ifdef MIGRAPH_DEBUG_OPT
void dump();
#endif
};
struct live_interval
{
live_interval() : segment({InvalidOffset, InvalidOffset, InvalidOffset, InvalidOffset, 0})
{
id = InvalidOffset;
def_point = InvalidOffset;
is_literal = false;
is_live_on_entry = false;
}
void add_use(int use) { use_points.push_front(use); }
int get_begin() const { return segment.begin; }
int get_end() const { return segment.end; }
long long get_offset() const { return segment.offset; }
#ifdef MIGRAPH_DEBUG_OPT
void dump();
#endif
live_range segment;
int id;
std::list<int> use_points;
int def_point;
shape result;
bool is_literal;
bool is_live_on_entry;
};
typedef live_interval* interval_ptr;
struct memory_coloring_impl
{
memory_coloring_impl(program* p) : p_program(p)
{
instr2_live.clear();
live_ranges.clear();
conflict_table.clear();
num_of_lives = 0;
max_value_number = -1;
required_bytes = 0;
operand_alias.clear();
earliest_end_point = -1;
}
bool allocate(interval_ptr);
void add_conflicts(std::set<int>& live_set, int val)
{
for(auto& iter : live_set)
{
conflict_table[iter].insert(val);
conflict_table[val].insert(iter);
}
}
void build();
void run();
void register_operand_alias();
void rewrite();
private:
static bool is_param(const instruction_ref ins) { return ins->op.name() == "@param"; }
static bool is_output_param(const instruction_ref ins)
{
return is_param(ins) && any_cast<builtin::param>(ins->op).parameter == "output";
}
static bool is_allocate(const instruction_ref ins) { return ins->op.name() == "hip::allocate"; }
static bool is_outline(const instruction_ref ins) { return ins->op.name() == "@outline"; }
static bool is_literal(const instruction_ref ins) { return ins->op.name() == "@literal"; }
static bool is_check_context(const instruction_ref ins)
{
return ins->op.name() == "check_context";
}
// get operand alias info. This is a temporary workaround.
int get_input_tie_ndx(const instruction_ref ins)
{
std::string name = ins->op.name();
if (operand_alias.find(name) != operand_alias.end())
return operand_alias[name];
int cnt = -1;
int last_allocate = -1;
for(auto&& arg : ins->arguments)
{
cnt++;
if(is_allocate(arg) || is_output_param(arg))
last_allocate = cnt;
}
if (last_allocate != -1)
operand_alias[name] = last_allocate;
else
assert("unknown operand alias");
return last_allocate;
}
#ifdef MIGRAPH_DEBUG_OPT
static bool is_disjoin(live_range& range1, live_range& range2)
{
if ((range1.size == 0) || (range2.size == 0))
return false;
long long end1 = range1.offset + range1.size - 1;
long long end2 = range2.offset + range2.size - 1;
return ((end1 < range2.offset) || (end2 < range1.offset));
}
void dump(const std::string);
void dump_program();
void dump_intervals();
void verify();
#endif
struct ordering
{
bool operator()(const interval_ptr i1, const interval_ptr i2) const
{
int len1 = i1->get_end() - i1->get_begin();
int len2 = i2->get_end() - i2->get_begin();
if(len1 != len2)
{
return (len1 < len2) ? true : false;
}
else if(i1->result.bytes() != i2->result.bytes())
{
return (i1->result.bytes() < i2->result.bytes()) ? true : false;
}
else
{
return i1->id > i2->id;
}
}
bool operator()(const live_range* i1, const live_range* i2) const
{
return (i1->offset > i2->offset);
}
};
program* p_program;
std::unordered_map<const instruction*, interval_ptr> instr2_live;
// universe of live intervals.
std::vector<live_interval> live_intervals;
// Map live range value number to live range.
std::unordered_map<int, live_range*> live_ranges;
// Map live range value number to a set of conflicting live ranges' value numbers.
std::unordered_map<int, std::set<int>> conflict_table;
// Priority queue for coloring.
std::priority_queue<interval_ptr, std::vector<interval_ptr>, ordering> alloc_queue;
std::unordered_map<std::string, int> operand_alias;
int num_of_lives;
int max_value_number;
long long required_bytes;
// The earliest program point where an live interval ends.
int earliest_end_point;
};
} // namespace migraph
#endif
...@@ -203,6 +203,25 @@ shape program::get_parameter_shape(std::string name) const ...@@ -203,6 +203,25 @@ shape program::get_parameter_shape(std::string name) const
return {}; return {};
} }
instruction_ref program::get_parameter(std::string name) const
{
auto ins = std::find_if(
impl->instructions.begin(), impl->instructions.end(), [&](const instruction& x) {
if(x.op.name() == "@param")
{
return any_cast<builtin::param>(x.op).parameter == name;
}
else
{
return false;
}
});
if(ins != this->end())
return ins;
else
return this->end();
}
std::unordered_map<std::string, shape> program::get_parameter_shapes() const std::unordered_map<std::string, shape> program::get_parameter_shapes() const
{ {
std::unordered_map<std::string, shape> result; std::unordered_map<std::string, shape> result;
...@@ -238,10 +257,10 @@ instruction_ref program::validate() const ...@@ -238,10 +257,10 @@ instruction_ref program::validate() const
[&](const instruction& i) { return !i.valid(impl->instructions.begin()); }); [&](const instruction& i) { return !i.valid(impl->instructions.begin()); });
} }
void program::compile(const target& t, tracer trace) void program::compile(const target& t, tracer trace, parameter_map params)
{ {
assert(this->validate() == impl->instructions.end()); assert(this->validate() == impl->instructions.end());
this->impl->ctx = t.get_context(); this->impl->ctx = t.get_context(params);
if(not trace.enabled() and enabled(MIGRAPH_TRACE_COMPILE{})) if(not trace.enabled() and enabled(MIGRAPH_TRACE_COMPILE{}))
trace = tracer{std::cout}; trace = tracer{std::cout};
trace(*this); trace(*this);
......
...@@ -13,3 +13,8 @@ target_link_libraries(migraph_cpu migraph Threads::Threads) ...@@ -13,3 +13,8 @@ target_link_libraries(migraph_cpu migraph Threads::Threads)
target_include_directories(migraph_cpu PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>) target_include_directories(migraph_cpu PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
target_include_directories(migraph_cpu PRIVATE ${BLAZE_INCLUDE}) target_include_directories(migraph_cpu PRIVATE ${BLAZE_INCLUDE})
target_compile_definitions(migraph_cpu PRIVATE -DBLAZE_USE_CPP_THREADS) target_compile_definitions(migraph_cpu PRIVATE -DBLAZE_USE_CPP_THREADS)
install (TARGETS migraph_cpu
LIBRARY DESTINATION /opt/rocm/lib)
install (DIRECTORY include/migraph DESTINATION /opt/rocm/include)
#ifndef MIGRAPH_GUARD_RTGLIB_CONTEXT_HPP #ifndef MIGRAPH_GUARD_RTGLIB_CONTEXT_HPP
#define MIGRAPH_GUARD_RTGLIB_CONTEXT_HPP #define MIGRAPH_GUARD_RTGLIB_CONTEXT_HPP
#include <migraph/argument.hpp>
#include <unordered_map>
namespace migraph { namespace migraph {
namespace cpu { namespace cpu {
using parameter_map = std::unordered_map<std::string, argument>;
struct context struct context
{ {
parameter_map params;
void finish() const {} void finish() const {}
}; };
......
...@@ -11,7 +11,7 @@ struct cpu_target ...@@ -11,7 +11,7 @@ struct cpu_target
{ {
std::string name() const; std::string name() const;
std::vector<pass> get_passes(migraph::context& ctx) const; std::vector<pass> get_passes(migraph::context& ctx) const;
migraph::context get_context() const { return context{}; } migraph::context get_context(parameter_map params = parameter_map()) const { return context{params}; }
}; };
} // namespace cpu } // namespace cpu
......
...@@ -26,9 +26,19 @@ add_library(migraph_gpu ...@@ -26,9 +26,19 @@ add_library(migraph_gpu
hip.cpp hip.cpp
target.cpp target.cpp
lowering.cpp lowering.cpp
lowering_memory_coloring.cpp
write_literals.cpp write_literals.cpp
rocblas.cpp rocblas.cpp
) )
rocm_clang_tidy_check(migraph_gpu) rocm_clang_tidy_check(migraph_gpu)
target_link_libraries(migraph_gpu migraph MIOpen migraph_device roc::rocblas) target_link_libraries(migraph_gpu migraph MIOpen migraph_device roc::rocblas)
target_include_directories(migraph_gpu PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>) target_include_directories(migraph_gpu PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
install (TARGETS migraph_gpu
LIBRARY DESTINATION /opt/rocm/lib)
install (DIRECTORY include/migraph DESTINATION /opt/rocm/include)
install (TARGETS migraph_device
LIBRARY DESTINATION /opt/rocm/lib)
install (DIRECTORY include/migraph DESTINATION /opt/rocm/include)
...@@ -6,12 +6,16 @@ ...@@ -6,12 +6,16 @@
#include <migraph/iterator_for.hpp> #include <migraph/iterator_for.hpp>
#include <migraph/ranges.hpp> #include <migraph/ranges.hpp>
#include <migraph/stringutils.hpp> #include <migraph/stringutils.hpp>
#include <migraph/pass_config.hpp>
namespace migraph { namespace migraph {
namespace gpu { namespace gpu {
void eliminate_workspace::apply(program& p) const void eliminate_workspace::apply(program& p) const
{ {
if (!enabled(MIGRAPH_DISABLE_MEMORY_COLORING{}))
return;
std::size_t n = 0; std::size_t n = 0;
std::vector<instruction_ref> allocs; std::vector<instruction_ref> allocs;
for(auto ins : iterator_for(p)) for(auto ins : iterator_for(p))
......
...@@ -90,6 +90,11 @@ argument from_gpu(argument arg) ...@@ -90,6 +90,11 @@ argument from_gpu(argument arg)
void gpu_sync() { hipDeviceSynchronize(); } void gpu_sync() { hipDeviceSynchronize(); }
void copy_to_gpu(char* dst, const char* src, std::size_t size)
{
hipMemcpy(dst, src, size, hipMemcpyHostToDevice);
}
} // namespace gpu } // namespace gpu
} // namespace migraph } // namespace migraph
...@@ -5,13 +5,17 @@ ...@@ -5,13 +5,17 @@
#include <migraph/gpu/rocblas.hpp> #include <migraph/gpu/rocblas.hpp>
#include <migraph/gpu/hip.hpp> #include <migraph/gpu/hip.hpp>
#include <unordered_map>
namespace migraph { namespace migraph {
namespace gpu { namespace gpu {
using parameter_map = std::unordered_map<std::string, argument>;
struct context struct context
{ {
shared<miopen_handle> handle; shared<miopen_handle> handle;
shared<rocblas_handle_ptr> rbhandle; shared<rocblas_handle_ptr> rbhandle;
parameter_map params;
argument scratch;
std::vector<argument> literals{}; std::vector<argument> literals{};
void finish() const { gpu_sync(); } void finish() const { gpu_sync(); }
}; };
......
...@@ -15,6 +15,8 @@ migraph::argument from_gpu(migraph::argument arg); ...@@ -15,6 +15,8 @@ migraph::argument from_gpu(migraph::argument arg);
void gpu_sync(); void gpu_sync();
void copy_to_gpu(char* dst, const char* src, std::size_t size);
struct hip_allocate struct hip_allocate
{ {
std::string tag{}; std::string tag{};
...@@ -30,22 +32,6 @@ struct hip_allocate ...@@ -30,22 +32,6 @@ struct hip_allocate
} }
}; };
struct hip_load
{
shape s;
std::size_t offset = 0;
std::string name() const { return "hip::load"; }
shape compute_shape(const std::vector<shape>& inputs) const
{
check_shapes{inputs}.has(1);
return s;
}
argument compute(context&, const shape&, const std::vector<argument>& args) const
{
return {s, args[0].data() + offset};
}
};
struct hip_sync struct hip_sync
{ {
std::string tag{}; std::string tag{};
...@@ -81,6 +67,21 @@ struct hip_write ...@@ -81,6 +67,21 @@ struct hip_write
} }
}; };
struct hip_memcpy
{
std::string name() const { return "hip_memcpy"; }
shape compute_shape(std::vector<shape> inputs) const { return inputs.at(1); }
argument compute(context&, shape output_shape, std::vector<argument> args) const
{
char* dst = args.at(0).data() + offset;
const char* src = args.at(1).data();
std::size_t size = args.at(1).get_shape().bytes();
copy_to_gpu(dst, src, size);
return {output_shape, dst};
}
std::size_t offset = 0;
};
} // namespace gpu } // namespace gpu
} // namespace migraph } // namespace migraph
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment