-
Notifications
You must be signed in to change notification settings - Fork 414
Add parameter to power-tune only cold starts #206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 32 commits
efd6ad0
89a255b
711e37d
4720586
f70677d
0445f32
4d8f554
f6d7ad1
32f9533
c0dd5ff
dd14172
c0192ec
5a2e515
93802fd
aa85838
1656b7e
79bb3b8
3c4b5d6
69edf22
6b9c85d
331de58
aad097c
2a547a6
4b58451
9a9b243
1979fb6
446fff2
e8b7d17
71aa0cb
40c221b
6f001da
940ecd8
000cd74
797f89c
355ea6f
18a8a65
aba4d63
103786c
38f5c96
d837b53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ module.exports.handler = async(event, context) => { | |
| preProcessorARN, | ||
| postProcessorARN, | ||
| discardTopBottom, | ||
| onlyColdStarts, | ||
| sleepBetweenRunsMs, | ||
| disablePayloadLogs, | ||
| } = await extractDataFromInput(event); | ||
|
|
@@ -35,8 +36,11 @@ module.exports.handler = async(event, context) => { | |
| const lambdaAlias = 'RAM' + value; | ||
| let results; | ||
|
|
||
| // fetch architecture from $LATEST | ||
| const {architecture, isPending} = await utils.getLambdaConfig(lambdaARN, lambdaAlias); | ||
| // defaulting the index to 0 as the index is required for onlyColdStarts | ||
| let aliasToInvoke = utils.buildAliasString(lambdaAlias, onlyColdStarts, 0); | ||
| // We need the architecture, regardless of onlyColdStarts or not | ||
| const {architecture, isPending} = await utils.getLambdaConfig(lambdaARN, aliasToInvoke); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at what the Initializer is doing (very similarly), I would consider merging utils.getLambdaPower and utils.getLambdaConfig since they are both using
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not blocking for this PR - just a reminder for myself in the future :) |
||
|
|
||
| console.log(`Detected architecture type: ${architecture}, isPending: ${isPending}`); | ||
|
|
||
| // pre-generate an array of N payloads | ||
|
|
@@ -49,12 +53,14 @@ module.exports.handler = async(event, context) => { | |
| payloads: payloads, | ||
| preARN: preProcessorARN, | ||
| postARN: postProcessorARN, | ||
| onlyColdStarts: onlyColdStarts, | ||
| sleepBetweenRunsMs: sleepBetweenRunsMs, | ||
| disablePayloadLogs: disablePayloadLogs, | ||
| }; | ||
|
|
||
| // wait if the function/alias state is Pending | ||
| if (isPending) { | ||
| // in the case of onlyColdStarts, we will verify each alias in the runInParallel or runInSeries | ||
| if (isPending && !onlyColdStarts) { | ||
| await utils.waitForAliasActive(lambdaARN, lambdaAlias); | ||
| console.log('Alias active'); | ||
| } | ||
|
|
@@ -68,7 +74,7 @@ module.exports.handler = async(event, context) => { | |
| // get base cost for Lambda | ||
| const baseCost = utils.lambdaBaseCost(utils.regionFromARN(lambdaARN), architecture); | ||
|
|
||
| return computeStatistics(baseCost, results, value, discardTopBottom); | ||
| return computeStatistics(baseCost, results, value, discardTopBottom, onlyColdStarts); | ||
| }; | ||
|
|
||
| const validateInput = (lambdaARN, value, num) => { | ||
|
|
@@ -97,8 +103,14 @@ const extractDiscardTopBottomValue = (event) => { | |
| // extract discardTopBottom used to trim values from average duration | ||
| let discardTopBottom = event.discardTopBottom; | ||
| if (typeof discardTopBottom === 'undefined') { | ||
| // default value for discardTopBottom | ||
| discardTopBottom = 0.2; | ||
| } | ||
| // In case of onlyColdStarts, we only have 1 invocation per alias, therefore we shouldn't discard any execution | ||
| if (event.onlyColdStarts){ | ||
| discardTopBottom = 0; | ||
| console.log('Setting discardTopBottom to 0, every invocation should be accounted when onlyColdStarts'); | ||
| } | ||
| // discardTopBottom must be between 0 and 0.4 | ||
| return Math.min(Math.max(discardTopBottom, 0.0), 0.4); | ||
| }; | ||
|
|
@@ -128,16 +140,22 @@ const extractDataFromInput = async(event) => { | |
| preProcessorARN: input.preProcessorARN, | ||
| postProcessorARN: input.postProcessorARN, | ||
| discardTopBottom: discardTopBottom, | ||
| onlyColdStarts: !!input.onlyColdStarts, | ||
| sleepBetweenRunsMs: sleepBetweenRunsMs, | ||
| disablePayloadLogs: !!input.disablePayloadLogs, | ||
| }; | ||
| }; | ||
|
|
||
| const runInParallel = async({num, lambdaARN, lambdaAlias, payloads, preARN, postARN, disablePayloadLogs}) => { | ||
| const runInParallel = async({num, lambdaARN, lambdaAlias, payloads, preARN, postARN, disablePayloadLogs, onlyColdStarts}) => { | ||
| const results = []; | ||
| // run all invocations in parallel ... | ||
| const invocations = utils.range(num).map(async(_, i) => { | ||
| const {invocationResults, actualPayload} = await utils.invokeLambdaWithProcessors(lambdaARN, lambdaAlias, payloads[i], preARN, postARN, disablePayloadLogs); | ||
| let aliasToInvoke = utils.buildAliasString(lambdaAlias, onlyColdStarts, i); | ||
| if (onlyColdStarts){ | ||
| await utils.waitForAliasActive(lambdaARN, aliasToInvoke); | ||
| console.log(`${aliasToInvoke} is active`); | ||
| } | ||
| const {invocationResults, actualPayload} = await utils.invokeLambdaWithProcessors(lambdaARN, aliasToInvoke, payloads[i], preARN, postARN, disablePayloadLogs); | ||
| // invocation errors return 200 and contain FunctionError and Payload | ||
| if (invocationResults.FunctionError) { | ||
| let errorMessage = 'Invocation error (running in parallel)'; | ||
|
|
@@ -150,11 +168,16 @@ const runInParallel = async({num, lambdaARN, lambdaAlias, payloads, preARN, post | |
| return results; | ||
| }; | ||
|
|
||
| const runInSeries = async({num, lambdaARN, lambdaAlias, payloads, preARN, postARN, sleepBetweenRunsMs, disablePayloadLogs}) => { | ||
| const runInSeries = async({num, lambdaARN, lambdaAlias, payloads, preARN, postARN, sleepBetweenRunsMs, disablePayloadLogs, onlyColdStarts}) => { | ||
| const results = []; | ||
| for (let i = 0; i < num; i++) { | ||
| let aliasToInvoke = utils.buildAliasString(lambdaAlias, onlyColdStarts, i); | ||
| // run invocations in series | ||
| const {invocationResults, actualPayload} = await utils.invokeLambdaWithProcessors(lambdaARN, lambdaAlias, payloads[i], preARN, postARN, disablePayloadLogs); | ||
| if (onlyColdStarts){ | ||
| await utils.waitForAliasActive(lambdaARN, aliasToInvoke); | ||
| console.log(`${aliasToInvoke} is active`); | ||
| } | ||
| const {invocationResults, actualPayload} = await utils.invokeLambdaWithProcessors(lambdaARN, aliasToInvoke, payloads[i], preARN, postARN, disablePayloadLogs); | ||
| // invocation errors return 200 and contain FunctionError and Payload | ||
| if (invocationResults.FunctionError) { | ||
| let errorMessage = 'Invocation error (running in series)'; | ||
|
|
@@ -168,10 +191,18 @@ const runInSeries = async({num, lambdaARN, lambdaAlias, payloads, preARN, postAR | |
| return results; | ||
| }; | ||
|
|
||
| const computeStatistics = (baseCost, results, value, discardTopBottom) => { | ||
| const computeStatistics = (baseCost, results, value, discardTopBottom, onlyColdStarts) => { | ||
| // use results (which include logs) to compute average duration ... | ||
|
|
||
| const durations = utils.parseLogAndExtractDurations(results); | ||
| if (onlyColdStarts) { | ||
| // we care about the init duration in this case | ||
| const initDurations = utils.parseLogAndExtractInitDurations(results); | ||
|
||
| // add init duration to total duration | ||
| initDurations.forEach((value, index) => { | ||
| durations[index] += value; | ||
| }); | ||
| } | ||
|
|
||
| const averageDuration = utils.computeAverageDuration(durations, discardTopBottom); | ||
| console.log('Average duration: ', averageDuration); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| 'use strict'; | ||
|
|
||
| const utils = require('./utils'); | ||
|
|
||
|
|
||
| module.exports.handler = async(event, context) => { | ||
| const {lambdaConfigurations, currConfig, lambdaARN} = validateInputs(event); | ||
| const currentIterator = lambdaConfigurations.iterator; | ||
| // publish version & assign alias (if present) | ||
| await utils.createPowerConfiguration(lambdaARN, currConfig.powerValue, currConfig.alias, currConfig.description); | ||
|
|
||
| const result = { | ||
| powerValues: lambdaConfigurations.powerValues, | ||
| initConfigurations: lambdaConfigurations.initConfigurations, | ||
| iterator: { | ||
| index: (currentIterator.index + 1), | ||
| count: currentIterator.count, | ||
| continue: ((currentIterator.index + 1) < currentIterator.count), | ||
| }, | ||
| }; | ||
|
|
||
| if (!result.iterator.continue) { | ||
| // clean the list of configuration if we're done iterating | ||
| delete result.initConfigurations; | ||
| } | ||
|
|
||
| return result; | ||
| }; | ||
| function validateInputs(event) { | ||
| if (!event.lambdaARN) { | ||
| throw new Error('Missing or empty lambdaARN'); | ||
| } | ||
| const lambdaARN = event.lambdaARN; | ||
| if (!(event.lambdaConfigurations && event.lambdaConfigurations.iterator && event.lambdaConfigurations.initConfigurations)){ | ||
| throw new Error('Invalid iterator for initialization'); | ||
| } | ||
| const iterator = event.lambdaConfigurations.iterator; | ||
| if (!(iterator.index >= 0 && iterator.index < iterator.count)){ | ||
| throw new Error(`Invalid iterator index: ${iterator.index}`); | ||
| } | ||
| const lambdaConfigurations = event.lambdaConfigurations; | ||
| const currIdx = iterator.index; | ||
| const currConfig = lambdaConfigurations.initConfigurations[currIdx]; | ||
| if (!(currConfig && currConfig.powerValue)){ | ||
| throw new Error(`Invalid init configuration: ${JSON.stringify(currConfig)}`); | ||
| } | ||
| return {lambdaConfigurations, currConfig, lambdaARN}; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.