diff --git a/examples/impls/ntt-test.yml b/examples/impls/ntt-test.yml new file mode 100644 index 000000000..3dc783438 --- /dev/null +++ b/examples/impls/ntt-test.yml @@ -0,0 +1,164 @@ +name: ntt-data-on-premise +description: https://github.com/Green-Software-Foundation/sci-guide/blob/dev/use-case-submissions/nttdatta-On-Premise-Web-system.md +tags: + kind: web + complexity: moderate + category: on-premise +initialize: + models: + - name: sci-m # a model that calculates m from te, tir, el, rr and rtor + kind: builtin + verbose: false + path: '' + - name: sci-o # a model that given e, i and m calculates a carbon value (e * i) + m + kind: builtin + verbose: false + path: '' +graph: + children: + layer-3-switch: # an advanced grouping node + pipeline: + - sci-m + - sci-o + config: + sci-m: + te: 251 # gCO2eq + tir: 3600 # 1 hour in s + el: 126144000 # 4 years in seconds + rr: 1 + tor: 1 + sci-o: + i: 457 # gCO2/kwh + observations: + - timestamp: 2023-07-06T00:00 + duration: 3600 + five-min-input-rate: 100 + five-min-output-rate: 100 + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + layer-2-switch: + pipeline: + - sci-m # duration & config -> embodied + - sci-o # energy & grid-carbon-intensity & embodied -> carbon + config: + sci-m: + te: 251 # gCO2eq + tir: 3600 # get from the duration field + el: 126144000 # 4 years in seconds + rr: 1 + tor: 1 + sci-o: + i: 457 # gCO2/kwh + children: + switch-1: + observations: + - timestamp: 2023-07-06T00:00 + duration: 1 + e-net: 5.41e-4 #kwh + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + switch-2: + observations: + - timestamp: 2023-07-06T00:00 + duration: 1 + e-net: 0 # no traffic at all + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + switch-3: + observations: + - timestamp: 2023-07-06T00:00 + duration: 1 + e-net: 6.37e-4 #kwh + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + switch-4: + observations: + - timestamp: 2023-07-06T00:00 + duration: 1 + e-net: 7.60e-9 #kwh + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + db-servers: + pipeline: + - sci-m # duration & config -> embodied + - sci-o # energy & grid-carbon-intensity & embodied -> carbon + config: + sci-m: + te: 6270000 # gCO2eq + tir: duration # get from the duration field + el: 126144000 # 4 years in seconds + rr: 1 + tor: 1 + sci-o: + i: 457 # gCO2/kwh + children: + db-server1: + observations: + - timestamp: 2023-07-06T00:00 + e-cpu: 0.258 + duration: 1 #s + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + db-server2: + observations: + - timestamp: 2023-07-06T00:00 + e-cpu: 0.193 + duration: 1 #s + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + app-servers: + pipeline: + - sci-m # duration & config -> embodied + - sci-o # energy & grid-carbon-intensity & embodied -> carbon + config: + sci-m: + te: 6270000 # gCO2eq + tir: duration # get from the duration field + el: 126144000 # 4 years in seconds + rr: 1 + tor: 1 + sci-o: + i: 457 # gCO2/kwh + children: + app-server1: + observations: + - timestamp: 2023-07-06T00:00 + duration: 1 + e-cpu: 0.149 + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + app-server2: + observations: + - timestamp: 2023-07-06T00:00 + duration: 1 + e-cpu: 0.147 + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + web-servers: + pipeline: + - sci-m # duration & config -> embodied + - sci-o # energy & grid-carbon-intensity & embodied -> carbon + config: + sci-m: + te: 6270000 # gCO2eq + tir: duration # get from the duration field + el: 126144000 # 4 years in seconds + rr: 1 + tor: 1 + sci-o: + i: 457 # gCO2/kwh + children: + web-server1: + observations: + - timestamp: 2023-07-06T00:00 + duration: 1 + e-cpu: 0.139 + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 + web-server2: + observations: + - timestamp: 2023-07-06T00:00 + duration: 1 + e-cpu: 0.116 + grid-ci: 951 # gCO2e/kWh + energy: 0.0004554559930455524 diff --git a/scripts/rimpl.ts b/scripts/rimpl.ts index c49584f79..d40676352 100644 --- a/scripts/rimpl.ts +++ b/scripts/rimpl.ts @@ -1,6 +1,6 @@ import {parseProcessArgument} from '../src/util/args'; import {ModelsUniverse} from '../src/util/models-universe'; -import {calculateImpactsBasedOnGraph} from '../src/util/rimpl-helpers'; +import {Supercomputer} from '../src/util/supercomputer'; import {openYamlFileAsObject, saveYamlFileAs} from '../src/util/yaml'; /** @@ -22,24 +22,20 @@ const rimplScript = async () => { // Lifecycle Initialize Models const modelsHandbook = new ModelsUniverse(); - impl.initialize.models.forEach((model: any) => modelsHandbook.writeDown(model) ); - // Initialize impact graph/computing - const childrenNames = Object.keys(impl.graph.children); - - await Promise.all( - childrenNames.map(calculateImpactsBasedOnGraph(impl, modelsHandbook)) - ); + // Lifecycle Computing + const ateruiComputer = new Supercomputer(impl, modelsHandbook); + const ompl = await ateruiComputer.compute(); if (!outputPath) { - console.log(JSON.stringify(impl)); + console.log(JSON.stringify(ompl)); return; } - saveYamlFileAs(impl, outputPath); + await saveYamlFileAs(ompl, outputPath); } catch (error) { console.error(error); } diff --git a/src/types/supercomputer.ts b/src/types/supercomputer.ts new file mode 100644 index 000000000..2a4447c19 --- /dev/null +++ b/src/types/supercomputer.ts @@ -0,0 +1,4 @@ +export type ChildInformation = { + name: string; + info: any; +}; diff --git a/src/util/models-universe.ts b/src/util/models-universe.ts index 67ee22165..fbb0fd507 100644 --- a/src/util/models-universe.ts +++ b/src/util/models-universe.ts @@ -102,4 +102,11 @@ export class ModelsUniverse { return this.initalizedModels; } + + /** + * Returns existing model by `name`. + */ + public async getInitializedModel(modelName: string, config: any) { + return await this.initalizedModels[modelName](config); + } } diff --git a/src/util/rimpl-helpers.ts b/src/util/rimpl-helpers.ts deleted file mode 100644 index cca841767..000000000 --- a/src/util/rimpl-helpers.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {ModelsUniverse} from './models-universe'; -import {Observatory} from './observatory'; - -/** - * Flattens config entries. - */ -export const flattenConfigValues = (config: any) => { - const configModelNames = Object.keys(config); - const values = configModelNames.reduce((acc: any, name: string) => { - acc = { - ...acc, - ...config[name], - }; - - return acc; - }, {}); - - return values; -}; - -/** - * For each graph builds params, then passes it to computing fn. - * Appends model config to each observation, then passes that information to Observatory. - * Then starts doing investigations for each model from pipeline. - * Grabs the result and returns it. - */ -export const calculateImpactsBasedOnGraph = - (impl: any, modelsHandbook: ModelsUniverse) => - async (childrenName: string) => { - const child = impl.graph.children[childrenName]; - const {pipeline, observations, config} = child; - - const extendedObservations = observations.map((observation: any) => ({ - ...observation, - ...flattenConfigValues(config), - })); - - const observatory = new Observatory(extendedObservations); - - for (const modelName of pipeline) { - const modelInstance: any = await modelsHandbook.initalizedModels[ - modelName - ](config && config[modelName]); - - await observatory.doInvestigationsWith(modelInstance); - } - - const impacts = observatory.getImpacts(); - impl.graph.children[childrenName].impacts = impacts; - - return impl; - }; diff --git a/src/util/supercomputer.ts b/src/util/supercomputer.ts new file mode 100644 index 000000000..1235adf65 --- /dev/null +++ b/src/util/supercomputer.ts @@ -0,0 +1,126 @@ +import {ModelsUniverse} from './models-universe'; +import {Observatory} from './observatory'; + +import {ChildInformation} from '../types/supercomputer'; + +/** + * Computer for `impl` documents. + */ +export class Supercomputer { + private olderChild: ChildInformation = {name: '', info: {}}; + private impl: any; + private modelsHandbook: ModelsUniverse; + + constructor(impl: any, modelsHandbook: ModelsUniverse) { + this.impl = impl; + this.modelsHandbook = modelsHandbook; + } + + /** + * Flattens config entries. + */ + private flattenConfigValues(config: any) { + const configModelNames = Object.keys(config); + const values = configModelNames.reduce((acc: any, name: string) => { + acc = { + ...acc, + ...config[name], + }; + + return acc; + }, {}); + + return values; + } + + /** + * Adds config entries to each obsercation object passed. + */ + private enrichObservations(observations: any[], config: any[]) { + const configValues = this.flattenConfigValues(config); + + return observations.map((observation: any) => ({ + ...observation, + ...configValues, + })); + } + + /** + * If child is top level, then initializes `this.olderChild`. + * If `children` object contains `children` property, it means observations are nested (calls compute again). + * Otherwise enriches observations, passes them to Observatory. + * For each model from pipeline Observatory gathers observations. Then results are stored. + */ + private async calculateImpactsForChild(childrenObject: any, params: any) { + const {childName, areChildrenNested} = params; + + if (!areChildrenNested) { + this.olderChild = { + name: childName, + info: this.impl.graph.children[childName], + }; + } + + const {pipeline, observations, config} = this.olderChild.info; + + if ('children' in childrenObject[childName]) { + return this.compute(childrenObject[childName].children, { + config, + }); + } + + const specificObservations = areChildrenNested + ? childrenObject[childName].observations + : observations; + + const enrichedObservations = this.enrichObservations( + specificObservations, + config + ); + + const observatory = new Observatory(enrichedObservations); + + for (const modelName of pipeline) { + const params = config && config[modelName]; + const modelInstance = await this.modelsHandbook.getInitializedModel( + modelName, + params + ); + + await observatory.doInvestigationsWith(modelInstance); + + if (areChildrenNested) { + this.impl.graph.children[this.olderChild.name].children[ + childName + ].impacts = observatory.getImpacts(); + + return; + } + } + + this.impl.graph.children[this.olderChild.name].impacts = + observatory.getImpacts(); + } + + /** + * Checks if object is top level children or nested, then runs through all children and calculates impacts. + */ + public async compute(childrenObject?: any, params?: any) { + const implOrChildren = childrenObject || this.impl; + const areChildrenNested = !!childrenObject; + const children = areChildrenNested + ? implOrChildren + : implOrChildren.graph.children; + const childrenNames = Object.keys(children); + + for (const childName of childrenNames) { + await this.calculateImpactsForChild(children, { + childName, + areChildrenNested, + ...params, + }); + } + + return this.impl; + } +}