Skip to content

Commit

Permalink
datamovement calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
gulang2019 committed Mar 25, 2023
1 parent 4926d47 commit e220d75
Show file tree
Hide file tree
Showing 15 changed files with 970 additions and 454 deletions.
69 changes: 69 additions & 0 deletions include/tileflow/loop-analysis/memory-state.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#pragma once

#include "loop-analysis/loop-state.hpp"

namespace analysis {

namespace TileFlow {


/**
* \brief the dataspaces
*/
struct MemoryState {
static const problem::Workload* workload_;
std::unordered_map<std::uint64_t, problem::OperationSpace> data_spaces_;

MemoryState& Union(const MemoryState& other);
MemoryState& Substract(const MemoryState& other);
MemoryState& Add(const MemoryState& other);
MemoryState& Intersect(const MemoryState& other);

// add
MemoryState& operator += (const MemoryState& other);
// union
MemoryState& operator |= (const MemoryState& other);
// intersect
MemoryState& operator &= (const MemoryState& other);
// substract
MemoryState& operator -= (const MemoryState& other);

MemoryState operator - (const MemoryState& other);

problem::OperationSpace& operator[] (int id) {
if (data_spaces_.count(id) == 0) {
data_spaces_.emplace(id, workload_);
}
return data_spaces_.at(id);
}

inline const problem::OperationSpace& at(std::uint64_t idx) const {
return data_spaces_.at(idx);
}

void insert(std::uint64_t spatial_id,
const problem::OperationPoint& low_point,
const problem::OperationPoint& high_point);

void insert(std::uint64_t spatial_id,
const problem::OperationSpace& data_space);

MemoryState() = default;

MemoryState(std::uint64_t id, const problem::OperationSpace& data_space){
data_spaces_.emplace(id, data_space);
}

const std::unordered_map<std::uint64_t, problem::OperationSpace>&
getDataSpaces() const {return data_spaces_;}


static void set_workload(const problem::Workload* workload) {
MemoryState::workload_ = workload;}

void show() const;
};

} // namespace TileFlow

} // namespace analysis
154 changes: 119 additions & 35 deletions include/tileflow/loop-analysis/nest-analysis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "tileflow/mapping/mapping.hpp"
#include "tileflow/common.hpp"
#include "tileflow/problem/problem.hpp"
#include "tileflow/loop-analysis/memory-state.hpp"

using mapping::TileFlow::Node;
using mapping::TileFlow::OpNode;
Expand All @@ -22,39 +23,37 @@ namespace analysis {
namespace TileFlow {

struct NodeConfig {
problem::Workload workload;
std::vector<problem::Shape::DataSpaceID> global_dataspace_ids;
// problem::Workload workload;
std::vector<problem::Shape::DataSpaceID> active_tensors;
loop::Nest loop_nest;
std::vector<problem::OperationPoint> vector_strides_;
std::vector<problem::OperationPoint> mold_low_;
std::vector<problem::OperationPoint> mold_high_;
std::vector<problem::OperationPoint> mold_high_residual_;
// the state to record the last_point_set and access counting
problem::PerDataSpace<AccessStatMatrix> access_stats_;

// StorageLevelCalculator
unsigned storage_level;
std::uint64_t fanout_x, fanout_y;

// SpatialOffsetsCalculator
std::uint64_t spatial_offset_x, spatial_offset_y, logical_x, logical_y;

std::unordered_map<problem::Shape::DataSpaceID,
std::vector<analysis::DataMovementInfo> > data_movements;

};

class NestAnalysis {
// opname X tensorname --> AccessPattern
std::unordered_map<std::string,
std::unordered_map<std::string,
problem::Shape::Projection> > access_patterns;

problem::TileFlow::Workloads& workloads_;
mapping::TileFlow::Mapping& mapping_;
model::Engine::Specs& arch_specs_;

void add_access_pattern(
problem::Shape::DataSpaceID producer_id,
const Node* producer,
problem::Shape::DataSpaceID consumer_id,
const Node* consumer,
std::unordered_map<const Node*, std::vector<problem::Shape::DataSpaceID> >& access_pattern);
/**
* \brief set the workload for tile nodes;
* \depends get_loopnest
*/
void get_tilewise_workloads();
const Node* consumer);
/**
* \brief set the loopnest for tile nodes;
*/
Expand All @@ -69,8 +68,28 @@ namespace TileFlow {
* \depends get_loopnest()
*/
void get_dimscale();
/**
* \brief get alive tensors for Tile Nodes
*/
void get_active_tensors();
/**
* \brief set the storage level for tile nodes;
*/
void get_storage_level();
/**
* \brief set the spatial offset for tile nodes;
* \depends get_storage_level()
*/
void get_spatial_offsets();

// this is set by get_datamovement
std::map<std::vector<unsigned>, ComputeInfo> compute_info_;
public:
NestAnalysis(problem::TileFlow::Workloads& workloads_, mapping::TileFlow::Mapping& mapping): workloads_(workloads_), mapping_(mapping){}
NestAnalysis(problem::TileFlow::Workloads& workloads_,
mapping::TileFlow::Mapping& mapping_,
model::Engine::Specs& arch_specs_)
: workloads_(workloads_), mapping_(mapping_), arch_specs_(arch_specs_){}

std::unordered_map<const Node*, NodeConfig> configs;

void analyze();
Expand All @@ -79,51 +98,90 @@ namespace TileFlow {
friend class DatamovementCalculator;
friend class DimScaleCalculator;
friend class LoopNestConstructor;
friend class StorageLevelCalculator;
};

struct ScreenShot{
/**
* \brief the API between pass on nodes.
*/
struct InputParam{
int num_epochs_;
const Node* curr_node_ = nullptr;
std::vector<unsigned> time_stamp_;
std::vector<unsigned> space_stamp_;
problem::OperationPoint cur_transform_;
const Node* node;
MemoryState init_working_set_;
};

class DatamovementCalculator: public mapping::TileFlow::Visitor {
std::map<std::vector<unsigned>, ComputeInfo> compute_info_;
std::ostream& operator<< (std::ostream& o, const InputParam& params);

struct RetVal{
MemoryState deltas_;
MemoryState last_working_set_;

RetVal() {}
RetVal(const problem::OperationPoint& low_pt,
const problem::OperationPoint& high_pt) {
deltas_.insert(0, low_pt, high_pt);
last_working_set_ = deltas_;
}
RetVal(problem::OperationSpace&& data_space_) {
deltas_.insert(0, data_space_);
last_working_set_ = deltas_;
}
};

std::ostream& operator<< (std::ostream& o, const RetVal& params);

class DatamovementCalculator: public mapping::TileFlow::Visitor {
NestAnalysis& analysis_;
std::stack<problem::OperationSpace> deltas_;
ScreenShot screen_shot_;
problem::OperationSpace computeDelta(const ScreenShot& screen_shot);
problem::OperationSpace combineDeltas(
const std::vector<problem::OperationSpace>& deltas,
ScopeNode::type_t type);
problem::Workload& workload_;
/**
* \brief the stack to pass parameter between nodes.
*/
std::stack<InputParam> input_stack_;
std::stack<RetVal> ret_stack_;
// const Node* curr_node_;
RetVal computeDelta(const InputParam& input);

void visitTile(const TileNode*) override;
void visitScope(const ScopeNode*) override;
void visitOp(const OpNode*) override;
public:
DatamovementCalculator(NestAnalysis& analysis): analysis_(analysis){}
DatamovementCalculator(NestAnalysis& analysis, problem::Workload& workload):
analysis_(analysis), workload_(workload){}
void run(const Node*) override;
friend class PerfectLoopnestAnalyzer;
};

class PerfectLoopnestAnalyzer: public analysis::NestAnalysis {
DatamovementCalculator& dm;
void ComputeTemporalWorkingSet(std::vector<analysis::LoopState>::reverse_iterator cur,
analysis::ElementState& cur_state) override;
DatamovementCalculator& dm_;
const InputParam& input_;
NodeConfig& config_;
RetVal ComputeTemporalWorkingSet();
RetVal ComputeSpatialWorkingSet();
void SimulateTemporalExecution();
void InitPerLevelDimScales() override;
void InitStorageBoundaries() override;
virtual problem::PerDataSpace<Point> GetCurrentTranslationVectors(
std::vector<analysis::LoopState>::reverse_iterator cur) override;
void FillSpatialDeltas(std::vector<analysis::LoopState>::reverse_iterator cur,
std::uint64_t base_index,
int extrapolation_stride,
std::vector<analysis::LoopState>::reverse_iterator extrapolation_level,
RetVal& ret_val);
problem::OperationSpace ComputeDeltas(
std::vector<analysis::LoopState>::reverse_iterator cur,
bool at_boundary);

std::uint64_t SpatialIDL2P(std::uint64_t logical_id);
public:
PerfectLoopnestAnalyzer(DatamovementCalculator& dm):analysis::NestAnalysis(), dm(dm){}
void init(problem::Workload*, loop::Nest*,
std::map<unsigned, std::uint64_t> fanoutX_map,
std::map<unsigned, std::uint64_t> fanoutY_map);
void calculateDataMovement();
PerfectLoopnestAnalyzer(
DatamovementCalculator& dm,
InputParam& input,
NodeConfig& config): dm_(dm), input_(input), config_(config){}
void init(problem::Workload*, loop::Nest*);
RetVal calculateDataMovement();


};
Expand Down Expand Up @@ -170,6 +228,32 @@ namespace TileFlow {
LoopNestConstructor(NestAnalysis& analysis): analysis_(analysis){}
void construct(const Node* root) {root->accept(this);}
};

class StorageLevelCalculator: public mapping::TileFlow::Visitor {
std::stack<unsigned> storage_levels_;
void visitTile(const TileNode*) override;
void visitScope(const ScopeNode*) override;
NestAnalysis& analysis_;
public:
StorageLevelCalculator(NestAnalysis& analysis): analysis_(analysis){
}
};

class SpatialOffsetsCalculator: public mapping::TileFlow::Visitor {
struct offset_t {
unsigned x, y;
unsigned max_x;

};
offset_t merge(const offset_t& o1, const offset_t& o2);
std::stack<offset_t> input_offsets, output_offsets;
void visitTile(const TileNode*) override;
void visitScope(const ScopeNode*) override;
NestAnalysis& analysis_;
public:
SpatialOffsetsCalculator(NestAnalysis& analysis): analysis_(analysis){
}
};
} // namespace TileFlow

} // namespace analysis
12 changes: 9 additions & 3 deletions include/tileflow/mapping/mapping.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,21 @@ class Node {
};

class ScopeNode: public Node {
public:
public:
enum type_t {
Sequential,
Sharing,
Parallel,
Pipeline
}type;

};
ScopeNode(config::CompoundConfigNode config);
void display(std::string prefix, bool recursive) const override;
void accept(Visitor* visitor) const {visitor->visitScope(this);}
ScopeNode::type_t get_scope_type() const {return type;}

private:
ScopeNode::type_t type;

};

class TileNode: public Node {
Expand All @@ -99,6 +104,7 @@ class TileNode: public Node {
loop::Nest constructLoopNest(
const std::map<std::string, problem::Shape::FactorizedDimensionID>&) const;
size_t n_level() const {return loopnests_.size();}
const std::vector<loop::TileFlow::Descriptor>& get_loops() const {return loopnests_;}
};

class OpNode: public Node {
Expand Down
1 change: 1 addition & 0 deletions include/tileflow/problem/problem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace TileFlow {
config::CompoundConfigNode coeffs_;

public:
Workloads() {common_shape_.UsesFlattening = false;}
bool add_workload(const std::string& name, std::shared_ptr<problem::TileFlow::Workload>& workload);
std::shared_ptr<problem::TileFlow::Workload> get_workload(const std::string & op_name) const {
return workloads_.at(op_name);
Expand Down
Loading

0 comments on commit e220d75

Please sign in to comment.