Skip to content

Commit

Permalink
Merge pull request #1008 from Green-Software-Foundation/granular-aggr…
Browse files Browse the repository at this point in the history
…egation

Granular aggregation
  • Loading branch information
narekhovhannisyan authored Sep 10, 2024
2 parents 490f283 + 922cbc4 commit a6b518f
Show file tree
Hide file tree
Showing 19 changed files with 259 additions and 142 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"dependencies": {
"@commitlint/cli": "^18.6.0",
"@commitlint/config-conventional": "^18.6.0",
"@grnsft/if-core": "^0.0.20",
"@grnsft/if-core": "^0.0.22",
"axios": "^1.7.2",
"csv-parse": "^5.5.6",
"csv-stringify": "^6.4.6",
Expand Down
47 changes: 40 additions & 7 deletions src/__tests__/if-run/builtins/time-sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ describe('builtins/time-sync:', () => {
type: 'horizontal',
};
const convertedMetrics = metricStorage.metrics.map((metric: string) => ({
[metric]: AGGREGATION_METHODS[2],
[metric]: {
time: AGGREGATION_METHODS[2],
component: AGGREGATION_METHODS[2],
},
}));
storeAggregationMetrics(...convertedMetrics);
});
Expand Down Expand Up @@ -483,7 +486,12 @@ describe('builtins/time-sync:', () => {
'allow-padding': true,
};

storeAggregationMetrics({carbon: 'sum'});
storeAggregationMetrics({
carbon: {
time: 'sum',
component: 'sum',
},
});

const timeModel = TimeSync(basicConfig, parametersMetadata, {});

Expand Down Expand Up @@ -598,8 +606,18 @@ describe('builtins/time-sync:', () => {
'allow-padding': true,
};

storeAggregationMetrics({'time-reserved': 'avg'});
storeAggregationMetrics({'resources-total': 'sum'});
storeAggregationMetrics({
'time-reserved': {
time: 'avg',
component: 'avg',
},
});
storeAggregationMetrics({
'resources-total': {
time: 'sum',
component: 'sum',
},
});

const timeModel = TimeSync(basicConfig, parametersMetadata, {});

Expand Down Expand Up @@ -647,8 +665,18 @@ describe('builtins/time-sync:', () => {
'time-reserved': 'time-allocated',
};

storeAggregationMetrics({'time-allocated': 'avg'});
storeAggregationMetrics({'resources-total': 'sum'});
storeAggregationMetrics({
'time-allocated': {
time: 'avg',
component: 'avg',
},
});
storeAggregationMetrics({
'resources-total': {
time: 'sum',
component: 'sum',
},
});

const timeModel = TimeSync(basicConfig, parametersMetadata, mapping);

Expand Down Expand Up @@ -722,7 +750,12 @@ describe('builtins/time-sync:', () => {
'allow-padding': true,
};

storeAggregationMetrics({'resources-total': 'none'});
storeAggregationMetrics({
'resources-total': {
time: 'none',
component: 'none',
},
});

const timeModel = TimeSync(basicConfig, parametersMetadata, {});

Expand Down
12 changes: 10 additions & 2 deletions src/__tests__/if-run/lib/aggregate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,23 @@ describe('lib/aggregate: ', () => {
type: 'horizontal',
};
const convertedMetrics = metricStorage.metrics.map((metric: string) => ({
[metric]: AGGREGATION_METHODS[2],
[metric]: {
time: AGGREGATION_METHODS[2],
component: AGGREGATION_METHODS[2],
},
}));

storeAggregationMetrics(...convertedMetrics);
});

describe('aggregate(): ', () => {
beforeAll(() => {
storeAggregationMetrics({carbon: 'sum'});
storeAggregationMetrics({
carbon: {
time: 'sum',
component: 'sum',
},
});
});

it('returns tree if aggregation is missing.', () => {
Expand Down
15 changes: 12 additions & 3 deletions src/__tests__/if-run/lib/explain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,19 +214,28 @@ describe('lib/explain: ', () => {
'cpu/energy': {
unit: 'kWh',
description: 'energy consumed by the cpu',
'aggregation-method': 'avg',
'aggregation-method': {
time: 'avg',
component: 'avg',
},
},
'memory/energy': {
unit: 'kWh',
description: 'energy consumed by data from memory',
'aggregation-method': 'sum',
'aggregation-method': {
time: 'sum',
component: 'sum',
},
},
},
outputs: {
'total/energy': {
unit: 'kWh',
description: 'sum of energy components',
'aggregation-method': 'sum',
'aggregation-method': {
time: 'sum',
component: 'sum',
},
},
},
},
Expand Down
40 changes: 30 additions & 10 deletions src/__tests__/if-run/util/aggregation-helper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {PluginParams} from '@grnsft/if-core/types';
import {AggregationParams} from '../../../common/types/manifest';

import {aggregateInputsIntoOne} from '../../../if-run/util/aggregation-helper';
import {AggregationMetric} from '../../../if-run/types/aggregation';
import {storeAggregationMetrics} from '../../../if-run/lib/aggregate';

import {STRINGS} from '../../../if-run/config';
Expand All @@ -20,16 +19,24 @@ describe('util/aggregation-helper: ', () => {
type: 'horizontal',
};
const convertedMetrics = metricStorage.metrics.map((metric: string) => ({
[metric]: AGGREGATION_METHODS[2],
[metric]: {
time: AGGREGATION_METHODS[2],
component: AGGREGATION_METHODS[2],
},
}));
storeAggregationMetrics(...convertedMetrics);
storeAggregationMetrics({carbon: 'sum'});
storeAggregationMetrics({
carbon: {
time: 'sum',
component: 'sum',
},
});
});

describe('aggregateInputsIntoOne(): ', () => {
it('throws error if aggregation criteria is not found in input.', () => {
const inputs: PluginParams[] = [{timestamp: '', duration: 10}];
const metrics: AggregationMetric[] = [{'cpu/utilization': 'sum'}];
const metrics: string[] = ['cpu/utilization'];
const isTemporal = false;

expect.assertions(2);
Expand All @@ -46,12 +53,17 @@ describe('util/aggregation-helper: ', () => {
});

it('passes `timestamp`, `duration` to aggregator if aggregation is temporal.', () => {
storeAggregationMetrics({carbon: 'sum'});
storeAggregationMetrics({
carbon: {
time: 'sum',
component: 'sum',
},
});
const inputs: PluginParams[] = [
{timestamp: '', duration: 10, carbon: 10},
{timestamp: '', duration: 10, carbon: 20},
];
const metrics: AggregationMetric[] = [{carbon: 'sum'}];
const metrics: string[] = ['carbon'];
const isTemporal = true;

const expectedValue = {
Expand All @@ -68,7 +80,7 @@ describe('util/aggregation-helper: ', () => {
{timestamp: '', duration: 10, carbon: 10},
{timestamp: '', duration: 10, carbon: 20},
];
const metrics: AggregationMetric[] = [{carbon: 'sum'}];
const metrics: string[] = ['carbon'];
const isTemporal = false;

const expectedValue = {
Expand All @@ -84,16 +96,24 @@ describe('util/aggregation-helper: ', () => {
type: 'horizontal',
};
const convertedMetrics = metricStorage.metrics.map((metric: string) => ({
[metric]: AGGREGATION_METHODS[2],
[metric]: {
time: AGGREGATION_METHODS[2],
component: AGGREGATION_METHODS[2],
},
}));
storeAggregationMetrics(...convertedMetrics);
storeAggregationMetrics({'cpu/utilization': 'avg'});
storeAggregationMetrics({
'cpu/utilization': {
time: 'avg',
component: 'avg',
},
});

const inputs: PluginParams[] = [
{timestamp: '', duration: 10, 'cpu/utilization': 10},
{timestamp: '', duration: 10, 'cpu/utilization': 90},
];
const metrics: AggregationMetric[] = [{'cpu/utilization': 'avg'}];
const metrics: string[] = ['cpu/utilization'];
const isTemporal = false;

const expectedValue = {
Expand Down
4 changes: 2 additions & 2 deletions src/common/types/manifest.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {z} from 'zod';
import {AggregationMethodTypes} from '@grnsft/if-core/types';
import {AggregationOptions} from '@grnsft/if-core/types';

import {manifestSchema} from '../util/validations';

Expand All @@ -11,7 +11,7 @@ export type PluginOptions = GlobalPlugins[string];

export type AggregationParams = Manifest['aggregation'];
export type AggregationMetricsWithMethod = {
[key: string]: AggregationMethodTypes;
[key: string]: AggregationOptions;
};

export type AggregationParamsSure = Extract<Manifest['aggregation'], {}>;
Expand Down
51 changes: 28 additions & 23 deletions src/common/util/validations.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {ZodIssue, ZodIssueCode, ZodSchema, z} from 'zod';
import {AGGREGATION_METHODS} from '@grnsft/if-core/consts';
import {ERRORS} from '@grnsft/if-core/utils';

import {STRINGS} from '../../if-run/config';
Expand All @@ -22,32 +23,35 @@ export const allDefined = (obj: Record<string | number | symbol, unknown>) =>
Object.values(obj).every(v => v !== undefined);

/**
* Schema for parameter metadata.
* Reusabe aggregation method schema for parameter metadata.
*/
const aggregationMethodSchema = z.object({
time: z.enum(AGGREGATION_METHODS),
component: z.enum(AGGREGATION_METHODS),
});

/**
* Reusable metadata schema.
*/
const metadataSchema = z
.record(
z.string(),
z.object({
unit: z.string(),
description: z.string(),
'aggregation-method': aggregationMethodSchema,
})
)
.optional()
.nullable();

/**
* Reusable parameter metadata schema.
*/
const parameterMetadataSchema = z
.object({
inputs: z
.record(
z.string(),
z.object({
unit: z.string(),
description: z.string(),
'aggregation-method': z.string(),
})
)
.optional()
.nullable(),
outputs: z
.record(
z.string(),
z.object({
unit: z.string(),
description: z.string(),
'aggregation-method': z.string(),
})
)
.optional()
.nullable(),
inputs: metadataSchema,
outputs: metadataSchema,
})
.optional();

Expand All @@ -71,6 +75,7 @@ export const manifestSchema = z.object({
.object({
metrics: z.array(z.string()),
type: z.enum(AGGREGATION_TYPES),
'skip-components': z.array(z.string()).optional(),
})
.optional()
.nullable(),
Expand Down
Loading

0 comments on commit a6b518f

Please sign in to comment.