Skip to content

Commit

Permalink
Merge pull request #1065 from Green-Software-Foundation/update-explai…
Browse files Browse the repository at this point in the history
…n-feature

Update explain feature
  • Loading branch information
jmcook1186 authored Oct 31, 2024
2 parents f4259da + c2bb2ac commit 0eb4834
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 125 deletions.
125 changes: 60 additions & 65 deletions src/__tests__/if-run/lib/explain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ describe('lib/explain: ', () => {
const mockData = {
pluginName: 'divide',
metadata: {kind: 'execute', inputs: undefined, outputs: undefined},
pluginData: {
path: 'builtin',
method: 'Divide',
},
};

addExplainData(mockData);
Expand Down Expand Up @@ -50,30 +46,29 @@ describe('lib/explain: ', () => {
},
},
},
pluginData: {
path: 'builtin',
method: 'Sum',
},
};

const expectedResult = {
'cpu/energy': {
plugins: ['sum'],
unit: 'kWh',
description: 'energy consumed by the cpu',
'aggregation-method': 'sum',
},
'network/energy': {
plugins: ['sum'],
unit: 'kWh',
description: 'energy consumed by data ingress and egress',
'aggregation-method': 'sum',
},
'energy-sum': {
plugins: ['sum'],
unit: 'kWh',
description: 'sum of energy components',
'aggregation-method': 'sum',
sum: {
inputs: {
'cpu/energy': {
unit: 'kWh',
description: 'energy consumed by the cpu',
'aggregation-method': 'sum',
},
'network/energy': {
unit: 'kWh',
description: 'energy consumed by data ingress and egress',
'aggregation-method': 'sum',
},
},
outputs: {
'energy-sum': {
unit: 'kWh',
description: 'sum of energy components',
'aggregation-method': 'sum',
},
},
},
};

Expand Down Expand Up @@ -111,42 +106,50 @@ describe('lib/explain: ', () => {
},
},
},
pluginData: {
path: 'builtin',
method: 'Sum',
},
};

const expectedResult = {
'cpu/energy': {
plugins: ['sum', 'sum-energy'],
unit: 'kWh',
description: 'energy consumed by the cpu',
'aggregation-method': 'sum',
},
'network/energy': {
plugins: ['sum'],
unit: 'kWh',
description: 'energy consumed by data ingress and egress',
'aggregation-method': 'sum',
},
'energy-sum': {
plugins: ['sum'],
unit: 'kWh',
description: 'sum of energy components',
'aggregation-method': 'sum',
},
'memory/energy': {
plugins: ['sum-energy'],
unit: 'kWh',
description: 'energy consumed by data from memory',
'aggregation-method': 'sum',
sum: {
inputs: {
'cpu/energy': {
unit: 'kWh',
description: 'energy consumed by the cpu',
'aggregation-method': 'sum',
},
'network/energy': {
unit: 'kWh',
description: 'energy consumed by data ingress and egress',
'aggregation-method': 'sum',
},
},
outputs: {
'energy-sum': {
unit: 'kWh',
description: 'sum of energy components',
'aggregation-method': 'sum',
},
},
},
'total/energy': {
plugins: ['sum-energy'],
unit: 'kWh',
description: 'sum of energy components',
'aggregation-method': 'sum',
'sum-energy': {
inputs: {
'cpu/energy': {
unit: 'kWh',
description: 'energy consumed by the cpu',
'aggregation-method': 'sum',
},
'memory/energy': {
unit: 'kWh',
description: 'energy consumed by data from memory',
'aggregation-method': 'sum',
},
},
outputs: {
'total/energy': {
unit: 'kWh',
description: 'sum of energy components',
'aggregation-method': 'sum',
},
},
},
};

Expand Down Expand Up @@ -184,10 +187,6 @@ describe('lib/explain: ', () => {
},
},
},
pluginData: {
path: 'builtin',
method: 'Sum',
},
};

expect.assertions(2);
Expand Down Expand Up @@ -239,10 +238,6 @@ describe('lib/explain: ', () => {
},
},
},
pluginData: {
path: 'builtin',
method: 'Sum',
},
};

expect.assertions(2);
Expand Down
8 changes: 6 additions & 2 deletions src/common/config/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ Incubation projects are experimental, offer no support guarantee, have minimal g
MANIFEST_IS_MISSING: 'Manifest is missing.',
DIRECTORY_NOT_FOUND: 'Directory not found.',
AGGREGATION_UNITS_NOT_MATCH: (param: string) =>
`Your manifest uses two instances of ${param} with different units. Please check that you are using consistent units for ${param} throughout your manifest.`,
`Your manifest uses two instances of \`${param}\` with different units. Please check that you are using consistent units for \`${param}\` throughout your manifest.`,
AGGREGATION_METHODS_NOT_MATCH: (param: string) =>
`Your manifest uses two instances of ${param} with different 'aggregation-method'. Please check that you are using right 'aggregation-method' for ${param} throughout your manifest.`,
`Your manifest uses two instances of \`${param}\` with different 'aggregation-method'. Please check that you are using right 'aggregation-method' for \`${param}\` throughout your manifest.`,
MISSING_INPUTS_PARAMETER: (pluginName: string) =>
`The inputs parameter metadata of the \`${pluginName}\` plugin is missing.`,
MISSING_OUTPUTS_PARAMETER: (pluginName: string) =>
`The outputs parameter metadata of the \`${pluginName}\` plugin is missing.`,
};
3 changes: 1 addition & 2 deletions src/if-run/lib/compute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ const computeNode = async (node: Node, params: ComputeParams): Promise<any> => {
addExplainData({
pluginName,
metadata: plugin.metadata,
pluginData: params.context.initialize!.plugins[pluginName],
});
}
}
Expand Down Expand Up @@ -184,6 +183,7 @@ const computeNode = async (node: Node, params: ComputeParams): Promise<any> => {
debugLogger.setExecutingPluginName(pluginName);

outputStorage = await plugin.execute(outputStorage, nodeConfig);

debugLogger.setExecutingPluginName();

node.outputs = outputStorage;
Expand All @@ -192,7 +192,6 @@ const computeNode = async (node: Node, params: ComputeParams): Promise<any> => {
addExplainData({
pluginName,
metadata: plugin.metadata,
pluginData: params.context.initialize!.plugins[pluginName],
});
}
}
Expand Down
147 changes: 99 additions & 48 deletions src/if-run/lib/explain.ts
Original file line number Diff line number Diff line change
@@ -1,82 +1,133 @@
import {ParameterMetadata} from '@grnsft/if-core/types';
import {ERRORS} from '@grnsft/if-core/utils';

import {STRINGS} from '../../common/config';

import {logger} from '../../common/util/logger';

import {ExplainParams, ExplainStorageType} from '../types/explain';

const {ManifestValidationError} = ERRORS;
const {AGGREGATION_UNITS_NOT_MATCH, AGGREGATION_METHODS_NOT_MATCH} = STRINGS;
const {
AGGREGATION_UNITS_NOT_MATCH,
AGGREGATION_METHODS_NOT_MATCH,
MISSING_INPUTS_PARAMETER,
MISSING_OUTPUTS_PARAMETER,
} = STRINGS;

/**
* Retrieves stored explain data.
*/
export const explain = () => storeExplainData.parameters;
export const explain = () => storeExplainData.plugins;

/**
* Manages the storage of explain data.
*/
const storeExplainData = (() => {
let parameter: ExplainStorageType = {};
let plugins: ExplainStorageType = {};

const parameterManager = {
get parameters() {
return parameter;
const pluginManager = {
get plugins() {
return plugins;
},
set parameters(value: ExplainStorageType) {
parameter = value;
set plugins(value: ExplainStorageType) {
plugins = value;
},
};

return parameterManager;
return pluginManager;
})();

/**
* Adds new explain data to the stored explain data.
*/
export const addExplainData = (params: ExplainParams) => {
const {pluginName, pluginData, metadata} = params;
const parameterMetadata = pluginData?.['parameter-metadata'] || metadata;
const parameters = storeExplainData.parameters;
const allParameters = {
...parameterMetadata?.inputs,
...parameterMetadata?.outputs,
} as ExplainStorageType;

Object.entries(allParameters).forEach(([name, meta]) => {
const existingParameter = parameters[name];

if (parameters[name]?.plugins?.includes(pluginName)) {
return;
}
const {pluginName, metadata} = params;
const plugin: ExplainStorageType = {
[pluginName]: {
inputs: metadata?.inputs ?? {},
outputs: metadata?.outputs ?? {},
},
};

if (existingParameter) {
if (meta.unit !== existingParameter.unit) {
throw new ManifestValidationError(AGGREGATION_UNITS_NOT_MATCH(name));
}
const isInputsMissing = !Object.keys(plugin[pluginName].inputs || {}).length;
const isOutputsMissing = !Object.keys(plugin[pluginName].outputs || {})
.length;

if (isInputsMissing) {
delete plugin[pluginName].inputs;

logger.warn(MISSING_INPUTS_PARAMETER(pluginName));
}

if (isOutputsMissing) {
delete plugin[pluginName].outputs;

logger.warn(MISSING_OUTPUTS_PARAMETER(pluginName));
}

checkMetadatas(metadata);

if (!isInputsMissing || !isOutputsMissing) {
storeExplainData.plugins = {
...storeExplainData.plugins,
...plugin,
};
}
};

if (
meta['aggregation-method'].component !==
existingParameter['aggregation-method'].component ||
meta['aggregation-method'].time !==
existingParameter['aggregation-method'].time
) {
throw new ManifestValidationError(AGGREGATION_METHODS_NOT_MATCH(name));
/**
* Checks if the 'unit' and 'aggregation-method' of the parameter are the same throughout the manifest
*/
const checkMetadatas = (metadata: {
inputs?: ParameterMetadata;
outputs?: ParameterMetadata;
}) => {
const inputsOutputsMetadata = {...metadata?.inputs, ...metadata?.outputs};
const storedParameters: any = {};

// Populate stored parameters with metadata from each plugin
Object.values(storeExplainData.plugins).forEach(plugin => {
const storedInputOutputMetadata = {...plugin.inputs, ...plugin.outputs};

Object.keys(storedInputOutputMetadata).forEach(parameter => {
if (!storedParameters[parameter]) {
storedParameters[parameter] = {
unit: storedInputOutputMetadata[parameter].unit,
'aggregation-method':
storedInputOutputMetadata[parameter]['aggregation-method'],
};
}
});
});

// Validate input-output metadata against stored parameters
Object.keys(inputsOutputsMetadata).forEach(parameterName => {
const parameter = inputsOutputsMetadata[parameterName];
const storedParameter = storedParameters[parameterName];

existingParameter.plugins.push(pluginName);
existingParameter.description =
meta.description || existingParameter.description;
} else {
parameters[name] = {
plugins: [pluginName],
unit: meta.unit,
description: meta.description,
'aggregation-method': meta['aggregation-method'],
};
if (
parameter &&
Object.keys(storedParameters).includes(parameterName) &&
storedParameter.unit !== parameter.unit
) {
throw new ManifestValidationError(
AGGREGATION_UNITS_NOT_MATCH(parameterName)
);
}
});

storeExplainData.parameters = {
...parameters,
};
// Check for aggregation-method mismatch
const inputAggregation = parameter['aggregation-method'];

if (
storedParameter &&
(storedParameter['aggregation-method']?.component !==
inputAggregation?.component ||
storedParameter['aggregation-method']?.time !== inputAggregation?.time)
) {
throw new ManifestValidationError(
AGGREGATION_METHODS_NOT_MATCH(parameterName)
);
}
});
};
Loading

0 comments on commit 0eb4834

Please sign in to comment.