diff --git a/README.md b/README.md index 189141a1..4975145d 100644 --- a/README.md +++ b/README.md @@ -325,6 +325,7 @@ int main() { [2024.07.27 - v2.6.1 - Chunel] * 提供`pipeline`的静态执行的方式,提供微任务机制 * 优化`event`(事件)机制,异步事件可以等待结束 +* 提供`pipeline`剪裁功能,用于删除`element`之间重复的依赖 diff --git a/src/GraphCtrl/GraphElement/GElement.cpp b/src/GraphCtrl/GraphElement/GElement.cpp index 8cf6dca7..ca63a5dc 100644 --- a/src/GraphCtrl/GraphElement/GElement.cpp +++ b/src/GraphCtrl/GraphElement/GElement.cpp @@ -566,4 +566,18 @@ CBool GElement::isDefaultBinding() const { return CGRAPH_DEFAULT_BINDING_INDEX == binding_index_; } + +CBool GElement::removeDepend(GElementPtr element) { + CGRAPH_ASSERT_NOT_NULL_THROW_ERROR(element) + CGRAPH_ASSERT_INIT_THROW_ERROR(false) + if (!dependence_.hasValue(element)) { + return false; + } + + dependence_.remove(element); + element->run_before_.remove(this); + left_depend_.store(dependence_.size(), std::memory_order_release); + return true; +} + CGRAPH_NAMESPACE_END diff --git a/src/GraphCtrl/GraphElement/GElement.h b/src/GraphCtrl/GraphElement/GElement.h index d83032e7..fb8761af 100644 --- a/src/GraphCtrl/GraphElement/GElement.h +++ b/src/GraphCtrl/GraphElement/GElement.h @@ -419,6 +419,13 @@ class GElement : public GElementObject, */ CBool isDefaultBinding() const; + /** + * 删除一个依赖的节点信息 + * @param element + * @return + */ + CBool removeDepend(GElement* element); + private: /** 状态相关信息 */ CBool done_ { false }; // 判定被执行结束 @@ -444,7 +451,7 @@ class GElement : public GElementObject, CBool is_prepared_ { false }; // 判断是否已经执行过 prepareRun() 方法 /** 图相关信息 */ - std::atomic left_depend_ { 0 }; // 当 left_depend_ 值为0的时候,即可以执行该element信息 + std::atomic left_depend_ { 0 }; // 当 left_depend_ 值为0的时候,即可以执行该element信息 USmallVector run_before_; // 被依赖的节点(后继) USmallVector dependence_; // 依赖的节点信息(前驱) GElement* belong_ { nullptr }; // 从属的element 信息,如为nullptr,则表示从属于 pipeline @@ -477,6 +484,7 @@ class GElement : public GElementObject, friend class GAspectObject; friend class GOptimizer; friend class GMaxParaOptimizer; + friend class GTrimOptimizer; friend class GSeparateOptimizer; friend class GElementRepository; friend class GPerf; diff --git a/src/GraphCtrl/GraphElement/GElementManager.cpp b/src/GraphCtrl/GraphElement/GElementManager.cpp index ea859997..2ccfe52f 100644 --- a/src/GraphCtrl/GraphElement/GElementManager.cpp +++ b/src/GraphCtrl/GraphElement/GElementManager.cpp @@ -176,6 +176,11 @@ CBool GElementManager::checkSerializable() { } +CSize GElementManager::trim() { + return GTrimOptimizer::trim(manager_elements_); +} + + CStatus GElementManager::process(const GSortedGElementPtrSet& elements) { CGRAPH_FUNCTION_BEGIN CGRAPH_ASSERT_NOT_NULL(engine_) diff --git a/src/GraphCtrl/GraphElement/GElementManager.h b/src/GraphCtrl/GraphElement/GElementManager.h index e2c479c8..bb800c5a 100644 --- a/src/GraphCtrl/GraphElement/GElementManager.h +++ b/src/GraphCtrl/GraphElement/GElementManager.h @@ -85,6 +85,12 @@ class GElementManager : public GElementObject, */ CBool checkSerializable(); + /** + * 剪裁多余的连边信息 + * @return + */ + CSize trim(); + /** * 加入数据,并且执行 * @param elements diff --git a/src/GraphCtrl/GraphElement/_GOptimizer/GMaxParaOptimizer.h b/src/GraphCtrl/GraphElement/_GOptimizer/GMaxParaOptimizer.h index 92b8c60a..3ec47736 100644 --- a/src/GraphCtrl/GraphElement/_GOptimizer/GMaxParaOptimizer.h +++ b/src/GraphCtrl/GraphElement/_GOptimizer/GMaxParaOptimizer.h @@ -41,39 +41,12 @@ class GMaxParaOptimizer : public GOptimizer { * 2. 根据路径,生成一张全连通图,然后将图取反,得到对应的补图(reGraph) * 3. 计算补图的最大团中元素个数(maxCliqueSize),即为当前dag的最大并行度 */ - const CSize size = elements.size(); - const auto& paths = GOptimizer::collectPaths(elements); // 根据传入的elements 的关系,分析出所有完整路径信息 - - std::vector> reGraph(size, std::vector(size, 1)); - buildReverseGraph(elements, paths, reGraph); // 根据路径信息,求出全连接图的补图 - - CSize maxCliqueSize = calcMaxCliqueSize(reGraph); // 计算最大团信息 + const auto& paths = collectPaths(elements); + const auto& reGraph = buildGraph(elements, paths, 0, 0, 1); + CSize maxCliqueSize = calcMaxCliqueSize(reGraph); return maxCliqueSize; } - /** - * 基于原有dag,计算出所有链路的全连接的补图,记作graph - * @param elements - * @param paths - * @param graph - * @return - */ - static CVoid buildReverseGraph(const GSortedGElementPtrSet& elements, - const std::vector>& paths, - std::vector>& graph) { - for (auto& path : paths) { - for (int i = 0; i < path.size() - 1; i++) { - // 这里的 find是一定能找到的。因为path的数据,是从elements中记录的 - int height = (int)std::distance(elements.begin(), elements.find(path[i])); - for (int j = i + 1; j < path.size(); j++) { - int column = (int)std::distance(elements.begin(), elements.find(path[j])); - graph[height][column] = 0; - graph[column][height] = 0; // 因为需要记录的是补图,所以将默认值设置为1,符合条件的设置为0 - } - } - } - } - /** * 计算当前最大团的大小 * @param graph diff --git a/src/GraphCtrl/GraphElement/_GOptimizer/GOptimizer.h b/src/GraphCtrl/GraphElement/_GOptimizer/GOptimizer.h index 5e8f02be..b03d4831 100644 --- a/src/GraphCtrl/GraphElement/_GOptimizer/GOptimizer.h +++ b/src/GraphCtrl/GraphElement/_GOptimizer/GOptimizer.h @@ -9,6 +9,8 @@ #ifndef CGRAPH_GOPTIMIZER_H #define CGRAPH_GOPTIMIZER_H +#include + #include "../GElementObject.h" CGRAPH_NAMESPACE_BEGIN @@ -54,6 +56,34 @@ class GOptimizer : public GElementObject { return paths; } + /** + * 构造对应的二维矩阵图 + * @param elements + * @param paths + * @param father + * @param son + * @param unlink + * @return + */ + static std::vector> buildGraph(const GSortedGElementPtrSet& elements, + const std::vector>& paths, + int father, int son, int unlink) { + const CSize size = elements.size(); + std::vector> graph(size, std::vector(size, unlink)); + for (auto& path : paths) { + for (int i = 0; i < path.size() - 1; i++) { + // 这里的 find是一定能找到的。因为path的数据,是从elements中记录的 + int height = (int)std::distance(elements.begin(), elements.find(path[i])); + for (int j = i + 1; j < path.size(); j++) { + int column = (int)std::distance(elements.begin(), elements.find(path[j])); + graph[height][column] = father; + graph[column][height] = son; + } + } + } + return graph; + } + friend class GPerf; }; diff --git a/src/GraphCtrl/GraphElement/_GOptimizer/GOptimizerInclude.h b/src/GraphCtrl/GraphElement/_GOptimizer/GOptimizerInclude.h index f3f49296..adf219de 100644 --- a/src/GraphCtrl/GraphElement/_GOptimizer/GOptimizerInclude.h +++ b/src/GraphCtrl/GraphElement/_GOptimizer/GOptimizerInclude.h @@ -12,5 +12,6 @@ #include "GOptimizer.h" #include "GMaxParaOptimizer.h" #include "GSeparateOptimizer.h" +#include "GTrimOptimizer.h" #endif //CGRAPH_GOPTIMIZERINCLUDE_H diff --git a/src/GraphCtrl/GraphElement/_GOptimizer/GTrimOptimizer.h b/src/GraphCtrl/GraphElement/_GOptimizer/GTrimOptimizer.h new file mode 100644 index 00000000..f092da2b --- /dev/null +++ b/src/GraphCtrl/GraphElement/_GOptimizer/GTrimOptimizer.h @@ -0,0 +1,59 @@ +/*************************** +@Author: Chunel +@Contact: chunel@foxmail.com +@File: GTrimOptimizer.h +@Time: 2024/9/1 13:59 +@Desc: +***************************/ + +#ifndef CGRAPH_GTRIMOPTIMIZER_H +#define CGRAPH_GTRIMOPTIMIZER_H + +#include +#include + +#include "GOptimizer.h" + +CGRAPH_NAMESPACE_BEGIN + +class GTrimOptimizer : public GOptimizer { + /** + * 针对图结构,做剪裁 + * @param elements + * @return + */ + static CSize trim(GSortedGElementPtrSet& elements) { + CSize trimNum = 0; + const auto& paths = collectPaths(elements); + auto graph = buildGraph(elements, paths, 1, 0, 0); + + for (auto* cur : elements) { + int idx = (int)std::distance(elements.begin(), elements.find(cur)); + GElementPtrArr candidates; + for (int i = 0; i < (int)cur->dependence_.size(); i++) { + int x = (int)std::distance(elements.begin(), elements.find(cur->dependence_[i])); + for (int j = i; j < (int)cur->dependence_.size(); j++) { + int y = (int)std::distance(elements.begin(), elements.find(cur->dependence_[j])); + if (1 == graph[x][y]) { + graph[x][idx] = 0; + candidates.push_back(cur->dependence_[i]); + } + } + } + + for (auto* candidate : candidates) { + if (cur->removeDepend(candidate)) { + trimNum++; + } + } + } + + return trimNum; + } + + friend class GElementManager; +}; + +CGRAPH_NAMESPACE_END + +#endif //CGRAPH_GTRIMOPTIMIZER_H diff --git a/src/GraphCtrl/GraphPipeline/GPipeline.cpp b/src/GraphCtrl/GraphPipeline/GPipeline.cpp index da0b1118..cbe9b1ed 100644 --- a/src/GraphCtrl/GraphPipeline/GPipeline.cpp +++ b/src/GraphCtrl/GraphPipeline/GPipeline.cpp @@ -262,11 +262,19 @@ GPipelinePtr GPipeline::setAutoCheck(CBool enable) { CSize GPipeline::getMaxPara() { + CGRAPH_ASSERT_INIT_THROW_ERROR(false) CGRAPH_ASSERT_NOT_NULL_THROW_ERROR(element_manager_) return element_manager_->calcMaxParaSize(); } +CSize GPipeline::trim() { + CGRAPH_ASSERT_INIT_THROW_ERROR(false) + CGRAPH_ASSERT_NOT_NULL_THROW_ERROR(element_manager_) + return element_manager_->trim(); +} + + CStatus GPipeline::makeSerial() { CGRAPH_FUNCTION_BEGIN CGRAPH_ASSERT_INIT(false) diff --git a/src/GraphCtrl/GraphPipeline/GPipeline.h b/src/GraphCtrl/GraphPipeline/GPipeline.h index 894c61e1..4ccf4e49 100644 --- a/src/GraphCtrl/GraphPipeline/GPipeline.h +++ b/src/GraphCtrl/GraphPipeline/GPipeline.h @@ -354,6 +354,12 @@ class GPipeline : public GPipelineObject, */ CSize getMaxPara(); + /** + * 针对图结构,做多余边剪裁 + * @return 返回值表示裁剪了多少条信息 + */ + CSize trim(); + /** * 将符合串行执行条件的pipeline,设定为串行执行的模式。可以大幅度提升运行性能。 * @return diff --git a/src/UtilsCtrl/Container/USmallVector.h b/src/UtilsCtrl/Container/USmallVector.h index 81306556..19c9b400 100644 --- a/src/UtilsCtrl/Container/USmallVector.h +++ b/src/UtilsCtrl/Container/USmallVector.h @@ -68,6 +68,22 @@ class USmallVector : public UtilsObject { memset(data_, 0, sizeof(T) * capacity_); } + CBool remove(const T& val) { + CBool result = false; + for (CSize i = 0; i < cur_index_; i++) { + if (data_[i] == val) { + for (CSize j = i; j < cur_index_ - 1; j++) { + data_[j] = data_[j + 1]; + } + cur_index_--; + result = true; + break; + } + } + return result; + } + + /** * 判断内部是否包含该值 * @param val @@ -122,6 +138,8 @@ class USmallVector : public UtilsObject { UIter end() const { return UIter(data_ + cur_index_); } T front() const { return data_[0]; } T back() const { return data_[cur_index_ - 1]; } + T& operator[](CSize index) { return data_[index]; } + const T& operator[](CSize index) const { return data_[index]; } private: T* data_ { nullptr }; // 存放具体数据