UNPKG

costreamjs

Version:

A high-performance streaming programming language for parallel architecture. This repo (js-version) is created for better using & reading & debugging.

168 lines (154 loc) 6.47 kB
import { Partition } from "./Partition" export class GreedyPartition extends Partition { constructor() { super() /** @type { vector<vector<FlatNode *>> } 划分的结果 */ this.X = [] /** @type { number[] } 划分的K个子图每个子图的总工作量 */ this.w = [] /** @type { number[] } 划分的K个子图每个子图的通信边的权重 */ this.edge = []; /** @type { number[] } 每个顶点的权重(总工作量) */ this.vwgt = []; /** @type { FlatNode[] } 候选节点的集合 */ this.S = []; /** @type { number } 节点的个数 */ this.nvtxs = 0 /** @type { number } 平衡因子 */ this.ee = 1.1 /** @type { Map<FlatNode,string> } 每个节点对应的状态 */ this.FlatNodeToState = new Map() } /** * 输入一个 flat, 返回该 flat 被 GAP 划分到的核号 */ getPart(flat) { return this.X.findIndex(nodes => nodes.includes(flat)) } /** * 输入 i, 返回 i 号子图的总工作量 */ getPartWeight(i) { return this.w[i] } /** * 输入 i,返回 i 号子图总通信量 */ getPartEdge(i) { return this.edge[i] } setCpuCoreNum(num) { this.mnparts = num this.X = Array.from({ length: num }).map(_ => []) // 初始化一个二维数组(先创建一个长度为 num 的一维数组, 再将每个位置映射为一个新数组) this.w = Array.from({ length: num }).fill(0) } } /** * 执行划分算法, 统计 ssg 中 flatNode 的工作量,作初始划分, 并计算通信量等数据, 最终将划分结果存入 this.X 中 * @param { StaticStreamGraph } ssg */ GreedyPartition.prototype.SssgPartition = function (ssg) { if (this.mnparts == 1) { this.X = [ssg.flatNodes] // 此时 X 的长度为1, 下标0对应了全部的 flatNodes this.finalParts = 1 } else { this.nvtxs = ssg.flatNodes.length this.setActorWorkload(ssg) this.doPartition(ssg) this.orderPartitionResult() } //将 X 的信息保存至 Partion 基类的两个 map 中 this.X.forEach((flatNodes, coreNum) => { flatNodes.forEach(flat => { this.FlatNode2PartitionNum.set(flat, coreNum) }) // 设置划分核号 - flatNode 节点的映射时, 对其按标号排序 this.PartitonNum2FlatNode.set(coreNum, flatNodes.sort((a,b)=>{ let a_num = a.name.split('_').pop(), b_num = b.name.split('_').pop() return a_num - b_num })) }) } /** * 设置每个节点的权重(实际上对每个节点: 权重 = 工作量*调度次数) */ GreedyPartition.prototype.setActorWorkload = function (ssg) { ssg.flatNodes.forEach((flat, idx) => { this.vwgt[idx] = flat.steadyCount * ssg.mapSteadyWork2FlatNode.get(flat) flat.vwgt = this.vwgt[idx] this.totalWork += this.vwgt[idx] }) } /** * 正式的划分过程 */ GreedyPartition.prototype.doPartition = function (ssg) { this.X[0] = ssg.flatNodes.slice() //首先划分全部点到0号核上 let we = this.totalWork / this.mnparts //每个子图平均工作量 let e = 2 - this.ee //满足系数(2-ee)即可 this.w[0] = this.totalWork for (let i = 1; i < this.mnparts; i++) { //开始构造子图 X[1] ~ X[n-1] this.S.length = 0 while (this.w[i] < we * e && this.X[0].length > 0) { if (this.S.length === 0) { //如果候选集合为空,选择X[0]中顶点权重最大的节点 var chooseFlat = this.X[0].reduce((a, b) => a.vwgt >= b.vwgt ? a : b) } else { //如果候选集合 S 不为空, 则选择 S 中收益函数值最大的节点 var chooseFlat = this.chooseMaxGain(this.X[i]) this.S.splice(this.S.indexOf(chooseFlat), 1) //从 S 中删除 } this.w[0] -= chooseFlat.vwgt this.X[0].splice(this.X[0].indexOf(chooseFlat), 1) this.X[i].push(chooseFlat) //将该节点加入 X[i]子图 this.w[i] += chooseFlat.vwgt //维护 X[i]子图的工作量 this.updateCandidate(ssg, chooseFlat) } } } /** * 移动一个节点后更新 候选节点集合S. * @summary 遍历chooseFlat 的所有上端节点&&下端节点, 如果该节点 在X[0]中 && 不在 S 中,则将它加入 S * @param { FlatNode } chooseFlat */ GreedyPartition.prototype.updateCandidate = function (ssg, chooseFlat) { let srcs = chooseFlat.inFlatNodes.filter(flat => this.X[0].includes(flat) && !this.S.includes(flat)) let dests = chooseFlat.outFlatNodes.filter(flat => this.X[0].includes(flat) && !this.S.includes(flat)) this.S = this.S.concat(srcs, dests) } /** * 选择 S 中增益函数最大的节点 * @description 增益函数 : 用 increase 表示减少与 Xi 子图通信带来的增益 , * 用 decrease 表示增加与 X[0] 的通信来带的损失, * 则 increase - decrease 就是增益函数 */ GreedyPartition.prototype.chooseMaxGain = function (Xi) { let gains = [] for (let i in this.S) { let flat = this.S[i] let increase = 0, decrease = 0 flat.inFlatNodes.forEach((src, idx) => { if (this.X[0].includes(src)) decrease += flat.steadyCount * flat.inPopWeights[idx] if (Xi.includes(src)) increase += flat.steadyCount * flat.inPopWeights[idx] }) flat.outFlatNodes.forEach((out, idx) => { if (this.X[0].includes(out)) decrease += flat.steadyCount * flat.outPushWeights[idx] if (Xi.includes(out)) increase += flat.steadyCount * flat.outPushWeights[idx] }) gains[i] = increase - decrease } let max = gains.indexOf(Math.max(...gains)) return this.S[max] } /** * 按子图负载由大到小排序,选择排序算法 */ GreedyPartition.prototype.orderPartitionResult = function () { this.X.forEach((flats, idx) => flats.w = this.w[idx]) this.X.sort((a, b) => b.w - a.w) this.w.sort((a, b) => b - a) this.X = this.X.filter(flats => flats.length != 0) //过滤掉不含节点的子图 this.X.forEach(flats=>flats.sort((a,b)=>a.name.match(/\d+/)[0] - b.name.match(/\d+/)[0])) //对一个子图按照名字序号升序排序 this.finalParts = this.X.length }