├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── analyse-code-size.js
├── analyse-lang.js
├── build.sh
├── csharp
├── .npmignore
├── Handler.cs
├── build.ps1
├── build.sh
├── project.csproj
└── serverless.yml
├── download-stats.js
├── golang
├── .npmignore
├── build.sh
├── handler.go
└── serverless.yml
├── invoke-functions.js
├── java
├── .npmignore
├── hello.iml
├── pom.xml
├── serverless.yml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── serverless
│ │ ├── ApiGatewayResponse.java
│ │ ├── Handler.java
│ │ └── Response.java
│ └── resources
│ └── log4j.properties
├── nodejs6-diff-package-size
├── bluebird-lodash-only
│ ├── handler.js
│ └── package.json
├── bluebird-only
│ ├── handler.js
│ └── package.json
├── extra-extra-extra-large-deps
│ ├── handler.js
│ └── package.json
├── extra-extra-large-deps
│ ├── handler.js
│ └── package.json
├── extra-large-deps
│ ├── handler.js
│ └── package.json
├── large-deps
│ ├── handler.js
│ └── package.json
├── no-deps
│ └── handler.js
└── serverless.yml
├── nodejs6
├── .npmignore
├── handler.js
└── serverless.yml
├── package.json
├── python
├── .npmignore
├── handler.py
└── serverless.yml
└── results.csv
/.gitignore:
--------------------------------------------------------------------------------
1 | .serverless/
2 |
3 | csharp/bin
4 | csharp/obj
5 |
6 | .idea/
7 |
8 | java/target/
9 |
10 | node_modules/
11 |
12 | golang/bin
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # package directories
2 | node_modules
3 | jspm_packages
4 |
5 | # Serverless directories
6 | .serverless
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Yan Cui
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # lambda-coldstart-comparison
2 | Comparing the coldstart time of AWS Lambda functions using a variety of language runtime and memory size
3 |
--------------------------------------------------------------------------------
/analyse-code-size.js:
--------------------------------------------------------------------------------
1 | // set this to your plot.ly account
2 | const username = process.env.USERNAME;
3 | const api_key = process.env.API_KEY;
4 |
5 | const _ = require('lodash');
6 | const co = require('co');
7 | const Promise = require('bluebird');
8 | const plotly = require('plotly')(username, api_key);
9 | const fs = Promise.promisifyAll(require("fs"));
10 | const math = require('mathjs');
11 | const Stats = require('fast-stats').Stats;
12 |
13 | const CodeSizes = {
14 | 'no-deps': 366, // 366 bytes
15 | 'bluebird-only': 185 * 1024, // 185KB
16 | 'bluebird-lodash-only': 895.8 * 1024, // 895.8KB
17 | 'large-deps': 5.5 * 1024 * 1024, // 5.5MB
18 | 'extra-large-deps': 14.3 * 1024 * 1024 // 14.3MB
19 | };
20 |
21 | let readStats = co.wrap(function* () {
22 | let contents = yield fs.readFileAsync('results.csv', 'utf-8');
23 | let rows = contents
24 | .split('\n')
25 | .filter(str => str.match(/aws-coldstart-nodejs6-package-size-dev-(.*)-(\d+\d*)/i))
26 | .map(str => {
27 | let parts = str.split(',');
28 | let funcName = parts[0];
29 | let matchRes = funcName.match(/aws-coldstart-nodejs6-package-size-dev-(.*)-(\d+\d*)/i);
30 |
31 | let group = matchRes[1];
32 | let memorySize = parseInt(matchRes[2]);
33 |
34 | return {
35 | function: parts[0],
36 | codeSize: CodeSizes[group],
37 | memorySize: memorySize,
38 | value: parts[2]
39 | };
40 | });
41 |
42 | return rows;
43 | });
44 |
45 | let boxPlot = co.wrap(function*() {
46 | let rows = _.sortBy(yield readStats(), r => r.memorySize);
47 |
48 | let byLang = {
49 | csharp: { y: [], x: [], type: "box", boxpoints: "all", name: "csharp" },
50 | java: { y: [], x: [], type: "box", boxpoints: "all", name: "java" },
51 | python: { y: [], x: [], type: "box", boxpoints: "all", name: "python" },
52 | nodejs6: { y: [], x: [], type: "box", boxpoints: "all", name: "nodejs6" }
53 | }
54 |
55 | rows.forEach(row => {
56 | byLang[row.lang].y.push(row.value);
57 | byLang[row.lang].x.push(`${row.memorySize}MB`);
58 | });
59 |
60 | let data = _.values(byLang);
61 | let layout = {
62 | yaxis: {
63 | title: "cold start (milliseconds)",
64 | zeroline: false
65 | },
66 | xaxis: {
67 | title: "memory size"
68 | },
69 | boxmode: "group"
70 | };
71 |
72 | let graphOptions = { filename: "cold-start-by-language", fileopt: "overwrite" };
73 | plotly.plot(data, graphOptions, function (err, msg) {
74 | let childProc = require('child_process');
75 | console.log(msg);
76 |
77 | childProc.exec(`open -a "Google Chrome" ${msg.url}`);
78 | });
79 |
80 | });
81 |
82 | let calcStats = co.wrap(function*() {
83 | let rows = yield readStats();
84 | let byCodeSize = _.groupBy(rows, r => `${r.codeSize}-${r.memorySize}MB`);
85 |
86 | let statsByCodeSize = _.mapValues(
87 | byCodeSize,
88 | rs => {
89 | let values = rs.map(r => r.value);
90 | let stats = new Stats();
91 | stats.push(values);
92 |
93 | return {
94 | codeSize: rs[0].codeSize,
95 | memorySize: rs[0].memorySize,
96 | stddev: math.std(values),
97 | mean: math.mean(values),
98 | median: math.median(values),
99 | '95%-tile': stats.percentile(95),
100 | '99%-tile': stats.percentile(99)
101 | };
102 | });
103 |
104 | console.log('codesize (bytes),memory size,std dev,mean,median,95%-tile,99%-tile');
105 | for (let x of _.values(statsByCodeSize)) {
106 | console.log(`${x.codeSize},${x.memorySize},${x.stddev},${x.mean},${x.median},${x['95%-tile']},${x['99%-tile']}`);
107 | }
108 | });
109 |
110 | // boxPlot();
111 | calcStats();
--------------------------------------------------------------------------------
/analyse-lang.js:
--------------------------------------------------------------------------------
1 | // set this to your plot.ly account
2 | const username = process.env.USERNAME;
3 | const api_key = process.env.API_KEY;
4 |
5 | const _ = require('lodash');
6 | const co = require('co');
7 | const Promise = require('bluebird');
8 | const plotly = require('plotly')(username, api_key);
9 | const fs = Promise.promisifyAll(require("fs"));
10 | const math = require('mathjs');
11 | const Stats = require('fast-stats').Stats;
12 |
13 | let readStats = co.wrap(function* () {
14 | let contents = yield fs.readFileAsync('results.csv', 'utf-8');
15 | let rows = contents
16 | .split('\n')
17 | .filter(str => str.match(/aws-coldstart-(\w+\w*)-dev-memory-(\d+\d*)/i))
18 | .map(str => {
19 | let parts = str.split(',');
20 | let funcName = parts[0];
21 | let matchRes = funcName.match(/aws-coldstart-(\w+\w*)-dev-memory-(\d+\d*)/i);
22 |
23 | let lang = matchRes[1];
24 | let memorySize = parseInt(matchRes[2]);
25 |
26 | return {
27 | function: parts[0],
28 | lang: lang,
29 | memorySize: memorySize,
30 | value: parts[2]
31 | };
32 | });
33 |
34 | return rows;
35 | });
36 |
37 | let boxPlot = co.wrap(function*() {
38 | let rows = _.sortBy(yield readStats(), r => r.memorySize);
39 |
40 | let byLang = {
41 | csharp: { y: [], x: [], type: "box", boxpoints: "all", name: "csharp" },
42 | java: { y: [], x: [], type: "box", boxpoints: "all", name: "java" },
43 | python: { y: [], x: [], type: "box", boxpoints: "all", name: "python" },
44 | nodejs6: { y: [], x: [], type: "box", boxpoints: "all", name: "nodejs6" },
45 | golang: { y:[], x: [], type: "box", boxpoints: "all", name: "golang"}
46 | }
47 |
48 | rows.forEach(row => {
49 | byLang[row.lang].y.push(row.value);
50 | byLang[row.lang].x.push(`${row.memorySize}MB`);
51 | });
52 |
53 | let data = _.values(byLang);
54 | let layout = {
55 | yaxis: {
56 | title: "cold start (milliseconds)",
57 | zeroline: false
58 | },
59 | xaxis: {
60 | title: "memory size"
61 | },
62 | boxmode: "group"
63 | };
64 |
65 | let graphOptions = { filename: "cold-start-by-language", fileopt: "overwrite" };
66 | plotly.plot(data, graphOptions, function (err, msg) {
67 | let childProc = require('child_process');
68 | console.log(msg);
69 |
70 | childProc.exec(`open -a "Google Chrome" ${msg.url}`);
71 | });
72 |
73 | });
74 |
75 | let calcStats = co.wrap(function*() {
76 | let rows = yield readStats();
77 | let byLangSize = _.groupBy(rows, r => `${r.lang}-${r.memorySize}MB`);
78 |
79 | let statsByLangSize = _.mapValues(
80 | byLangSize,
81 | rs => {
82 | let values = rs.map(r => r.value);
83 | let stats = new Stats();
84 | stats.push(values);
85 |
86 | return {
87 | lang: rs[0].lang,
88 | memorySize: rs[0].memorySize,
89 | stddev: math.std(values),
90 | mean: math.mean(values),
91 | median: math.median(values),
92 | '95%-tile': stats.percentile(95),
93 | '99%-tile': stats.percentile(99)
94 | };
95 | });
96 |
97 | console.log('lang,memory size,std dev,mean,median,95%-tile,99%-tile');
98 | for (let x of _.values(statsByLangSize)) {
99 | console.log(`${x.lang},${x.memorySize},${x.stddev},${x.mean},${x.median},${x['95%-tile']},${x['99%-tile']}`);
100 | }
101 | });
102 |
103 | boxPlot();
104 | // calcStats();
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | declare -a folders=("csharp" "java" "python" "golang" "nodejs6" "nodejs6-diff-package-size")
3 |
4 | export AWS_PROFILE=personal
5 |
6 | for i in `seq 1 10`;
7 | do
8 | for folder in "${folders[@]}"
9 | do
10 | cd $folder
11 | pwd
12 |
13 | sls deploy
14 |
15 | cd ..
16 | done
17 |
18 | node invoke-functions.js
19 | done
20 |
--------------------------------------------------------------------------------
/csharp/.npmignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 |
24 | # Visual Studio 2015 cache/options directory
25 | .vs/
26 | # Uncomment if you have tasks that create the project's static files in wwwroot
27 | #wwwroot/
28 |
29 | # MSTest test Results
30 | [Tt]est[Rr]esult*/
31 | [Bb]uild[Ll]og.*
32 |
33 | # NUNIT
34 | *.VisualState.xml
35 | TestResult.xml
36 |
37 | # Build Results of an ATL Project
38 | [Dd]ebugPS/
39 | [Rr]eleasePS/
40 | dlldata.c
41 |
42 | # DNX
43 | project.lock.json
44 | artifacts/
45 |
46 | *_i.c
47 | *_p.c
48 | *_i.h
49 | *.ilk
50 | *.meta
51 | *.obj
52 | *.pch
53 | *.pdb
54 | *.pgc
55 | *.pgd
56 | *.rsp
57 | *.sbr
58 | *.tlb
59 | *.tli
60 | *.tlh
61 | *.tmp
62 | *.tmp_proj
63 | *.log
64 | *.vspscc
65 | *.vssscc
66 | .builds
67 | *.pidb
68 | *.svclog
69 | *.scc
70 |
71 | # Chutzpah Test files
72 | _Chutzpah*
73 |
74 | # Visual C++ cache files
75 | ipch/
76 | *.aps
77 | *.ncb
78 | *.opendb
79 | *.opensdf
80 | *.sdf
81 | *.cachefile
82 |
83 | # Visual Studio profiler
84 | *.psess
85 | *.vsp
86 | *.vspx
87 | *.sap
88 |
89 | # TFS 2012 Local Workspace
90 | $tf/
91 |
92 | # Guidance Automation Toolkit
93 | *.gpState
94 |
95 | # ReSharper is a .NET coding add-in
96 | _ReSharper*/
97 | *.[Rr]e[Ss]harper
98 | *.DotSettings.user
99 |
100 | # JustCode is a .NET coding add-in
101 | .JustCode
102 |
103 | # TeamCity is a build add-in
104 | _TeamCity*
105 |
106 | # DotCover is a Code Coverage Tool
107 | *.dotCover
108 |
109 | # NCrunch
110 | _NCrunch_*
111 | .*crunch*.local.xml
112 | nCrunchTemp_*
113 |
114 | # MightyMoose
115 | *.mm.*
116 | AutoTest.Net/
117 |
118 | # Web workbench (sass)
119 | .sass-cache/
120 |
121 | # Installshield output folder
122 | [Ee]xpress/
123 |
124 | # DocProject is a documentation generator add-in
125 | DocProject/buildhelp/
126 | DocProject/Help/*.HxT
127 | DocProject/Help/*.HxC
128 | DocProject/Help/*.hhc
129 | DocProject/Help/*.hhk
130 | DocProject/Help/*.hhp
131 | DocProject/Help/Html2
132 | DocProject/Help/html
133 |
134 | # Click-Once directory
135 | publish/
136 |
137 | # Publish Web Output
138 | *.[Pp]ublish.xml
139 | *.azurePubxml
140 | # TODO: Comment the next line if you want to checkin your web deploy settings
141 | # but database connection strings (with potential passwords) will be unencrypted
142 | *.pubxml
143 | *.publishproj
144 |
145 | # NuGet Packages
146 | *.nupkg
147 | # The packages folder can be ignored because of Package Restore
148 | **/packages/*
149 | # except build/, which is used as an MSBuild target.
150 | !**/packages/build/
151 | # Uncomment if necessary however generally it will be regenerated when needed
152 | #!**/packages/repositories.config
153 | # NuGet v3's project.json files produces more ignoreable files
154 | *.nuget.props
155 | *.nuget.targets
156 |
157 | # Microsoft Azure Build Output
158 | csx/
159 | *.build.csdef
160 |
161 | # Microsoft Azure Emulator
162 | ecf/
163 | rcf/
164 |
165 | # Microsoft Azure ApplicationInsights config file
166 | ApplicationInsights.config
167 |
168 | # Windows Store app package directory
169 | AppPackages/
170 | BundleArtifacts/
171 |
172 | # Visual Studio cache files
173 | # files ending in .cache can be ignored
174 | *.[Cc]ache
175 | # but keep track of directories ending in .cache
176 | !*.[Cc]ache/
177 |
178 | # Others
179 | ClientBin/
180 | ~$*
181 | *~
182 | *.dbmdl
183 | *.dbproj.schemaview
184 | *.pfx
185 | *.publishsettings
186 | node_modules/
187 | orleans.codegen.cs
188 |
189 | # RIA/Silverlight projects
190 | Generated_Code/
191 |
192 | # Backup & report files from converting an old project file
193 | # to a newer Visual Studio version. Backup files are not needed,
194 | # because we have git ;-)
195 | _UpgradeReport_Files/
196 | Backup*/
197 | UpgradeLog*.XML
198 | UpgradeLog*.htm
199 |
200 | # SQL Server files
201 | *.mdf
202 | *.ldf
203 |
204 | # Business Intelligence projects
205 | *.rdl.data
206 | *.bim.layout
207 | *.bim_*.settings
208 |
209 | # Microsoft Fakes
210 | FakesAssemblies/
211 |
212 | # GhostDoc plugin setting file
213 | *.GhostDoc.xml
214 |
215 | # Node.js Tools for Visual Studio
216 | .ntvs_analysis.dat
217 |
218 | # Visual Studio 6 build log
219 | *.plg
220 |
221 | # Visual Studio 6 workspace options file
222 | *.opt
223 |
224 | # Visual Studio LightSwitch build output
225 | **/*.HTMLClient/GeneratedArtifacts
226 | **/*.DesktopClient/GeneratedArtifacts
227 | **/*.DesktopClient/ModelManifest.xml
228 | **/*.Server/GeneratedArtifacts
229 | **/*.Server/ModelManifest.xml
230 | _Pvt_Extensions
231 |
232 | # Paket dependency manager
233 | .paket/paket.exe
234 |
235 | # FAKE - F# Make
236 | .fake/
237 | *.orig
238 |
239 | # macOS
240 | .DS_Store
241 |
242 | # JetBrains Rider C# IDE
243 | .idea*
244 |
245 | # Serverless directories
246 | .serverless
247 |
--------------------------------------------------------------------------------
/csharp/Handler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Amazon.Lambda.Core;
3 | using Amazon.Lambda.APIGatewayEvents;
4 | using System.Net;
5 |
6 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
7 | namespace AwsDotnetCsharp
8 | {
9 | public class Handler
10 | {
11 | public APIGatewayProxyResponse Hello(APIGatewayProxyRequest request, ILambdaContext context)
12 | {
13 | return new APIGatewayProxyResponse {
14 | StatusCode = (int)HttpStatusCode.OK,
15 | Body = "Hello"
16 | };
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/csharp/build.ps1:
--------------------------------------------------------------------------------
1 | # from http://stackoverflow.com/questions/1153126/how-to-create-a-zip-archive-with-powershell#answer-13302548
2 | function ZipFiles( $zipfilename, $sourcedir )
3 | {
4 | Add-Type -Assembly System.IO.Compression.FileSystem
5 | $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
6 | [System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir,
7 | $zipfilename, $compressionLevel, $false)
8 | }
9 |
10 | dotnet restore
11 | dotnet publish -c release
12 | if ($LASTEXITCODE -ne 0) { return }
13 |
14 | $publishDirectory = "bin/release/netcoreapp1.0/publish"
15 | $packageName = "deploy-package.zip"
16 |
17 | rm "$publishDirectory/$packageName" -ErrorAction SilentlyContinue
18 | ZipFiles "$(pwd)/$packageName" "$(pwd)/$publishDirectory"
19 | mv "$packageName" $publishDirectory
20 |
--------------------------------------------------------------------------------
/csharp/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | dotnet restore
4 | dotnet lambda package -c Release -f netcoreapp2.0 -o bin/deploy-package.zip
--------------------------------------------------------------------------------
/csharp/project.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CsharpHandlers
5 | CsharpHandlers
6 | netcoreapp2.0
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/csharp/serverless.yml:
--------------------------------------------------------------------------------
1 | service: aws-coldstart-csharp
2 |
3 | provider:
4 | name: aws
5 | runtime: dotnetcore2.0
6 | versionFunctions: false
7 |
8 | package:
9 | artifact: bin/deploy-package.zip
10 |
11 | functions:
12 | memory-128:
13 | handler: CsharpHandlers::AwsDotnetCsharp.Handler::Hello
14 | memorySize: 128
15 |
16 | memory-256:
17 | handler: CsharpHandlers::AwsDotnetCsharp.Handler::Hello
18 | memorySize: 256
19 |
20 | memory-512:
21 | handler: CsharpHandlers::AwsDotnetCsharp.Handler::Hello
22 | memorySize: 512
23 |
24 | memory-1024:
25 | handler: CsharpHandlers::AwsDotnetCsharp.Handler::Hello
26 | memorySize: 1024
27 |
28 | memory-1536:
29 | handler: CsharpHandlers::AwsDotnetCsharp.Handler::Hello
30 | memorySize: 1536
--------------------------------------------------------------------------------
/download-stats.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _ = require('lodash');
4 | const co = require('co');
5 | const Promise = require('bluebird');
6 | const AWS = require('aws-sdk');
7 | AWS.config.region = 'us-east-1';
8 | const cloudwatch = Promise.promisifyAll(new AWS.CloudWatch());
9 | const Lambda = new AWS.Lambda();
10 |
11 | const START_TIME = new Date('2017-06-07T01:00:00.000Z');
12 | const DAYS = 2;
13 | const ONE_DAY = 24 * 60 * 60 * 1000;
14 |
15 | let addDays = (startDt, n) => new Date(startDt.getTime() + ONE_DAY * n);
16 |
17 | let getFuncStats = co.wrap(function* (funcName) {
18 | let getStats = co.wrap(function* (startTime, endTime) {
19 | let req = {
20 | MetricName: 'Duration',
21 | Namespace: 'AWS/Lambda',
22 | Period: 60,
23 | Dimensions: [ { Name: 'FunctionName', Value: funcName } ],
24 | Statistics: [ 'Maximum' ],
25 | Unit: 'Milliseconds',
26 | StartTime: startTime,
27 | EndTime: endTime
28 | };
29 | let resp = yield cloudwatch.getMetricStatisticsAsync(req);
30 |
31 | return resp.Datapoints.map(dp => {
32 | return {
33 | timestamp: dp.Timestamp,
34 | value: dp.Maximum
35 | };
36 | });
37 | });
38 |
39 | let stats = [];
40 | for (let i = 0; i < DAYS; i++) {
41 | // CloudWatch only allows us to query 1440 data points per request, which
42 | // at 1 min period is 24 hours
43 | let startTime = addDays(START_TIME, i);
44 | let endTime = addDays(startTime, 1);
45 | let oneDayStats = yield getStats(startTime, endTime);
46 |
47 | stats = stats.concat(oneDayStats);
48 | }
49 |
50 | return _.sortBy(stats, s => s.timestamp);
51 | });
52 |
53 | let listFunctions = co.wrap(function* (marker, acc) {
54 | acc = acc || [];
55 |
56 | let resp = yield Lambda.listFunctions({ Marker: marker, MaxItems: 100 }).promise();
57 |
58 | let functions = resp.Functions
59 | .map(f => f.FunctionName)
60 | .filter(fn => fn.includes("aws-coldstart") && !fn.endsWith("run"));
61 |
62 | acc = acc.concat(functions);
63 |
64 | if (resp.NextMarker) {
65 | return yield listFunctions(resp.NextMarker, acc);
66 | } else {
67 | return acc;
68 | }
69 | });
70 |
71 | listFunctions()
72 | .then(co.wrap(function* (funcs) {
73 | for (let func of funcs) {
74 | let stats = yield getFuncStats(func);
75 | stats.forEach(stat => console.log(`${func},${stat.timestamp},${stat.value}`));
76 | }
77 | }));
--------------------------------------------------------------------------------
/golang/.npmignore:
--------------------------------------------------------------------------------
1 | .serverless
2 | bin
--------------------------------------------------------------------------------
/golang/build.sh:
--------------------------------------------------------------------------------
1 | GOOS=linux GOARCH=amd64 go build -o bin/handler handler.go
2 | cd bin
3 | zip deploy-package.zip handler
--------------------------------------------------------------------------------
/golang/handler.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/aws/aws-lambda-go/events"
5 | "github.com/aws/aws-lambda-go/lambda"
6 | )
7 |
8 | // Hello just returns Hello
9 | func Hello() (events.APIGatewayProxyResponse, error) {
10 | return events.APIGatewayProxyResponse{
11 | Body: "hello",
12 | StatusCode: 200,
13 | }, nil
14 | }
15 |
16 | func main() {
17 | lambda.Start(Hello)
18 | }
19 |
--------------------------------------------------------------------------------
/golang/serverless.yml:
--------------------------------------------------------------------------------
1 | service: aws-coldstart-golang
2 |
3 | provider:
4 | name: aws
5 | runtime: go1.x
6 | versionFunctions: false
7 |
8 | package:
9 | artifact: bin/deploy-package.zip
10 |
11 | functions:
12 | memory-128:
13 | handler: handler
14 | memorySize: 128
15 |
16 | memory-256:
17 | handler: handler
18 | memorySize: 256
19 |
20 | memory-512:
21 | handler: handler
22 | memorySize: 512
23 |
24 | memory-1024:
25 | handler: handler
26 | memorySize: 1024
27 |
28 | memory-1536:
29 | handler: handler
30 | memorySize: 1536
--------------------------------------------------------------------------------
/invoke-functions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const co = require('co');
4 | const AWS = require('aws-sdk');
5 | AWS.config.region = 'us-east-1';
6 | const Lambda = new AWS.Lambda();
7 |
8 | let functions = [];
9 |
10 | let listFunctions = co.wrap(function* (marker, acc) {
11 | acc = acc || [];
12 |
13 | let resp = yield Lambda.listFunctions({ Marker: marker, MaxItems: 100 }).promise();
14 |
15 | let functions = resp.Functions
16 | .map(f => f.FunctionName)
17 | .filter(fn => fn.includes("aws-coldstart") && !fn.endsWith("run"));
18 |
19 | acc = acc.concat(functions);
20 |
21 | if (resp.NextMarker) {
22 | return yield listFunctions(resp.NextMarker, acc);
23 | } else {
24 | return acc;
25 | }
26 | });
27 |
28 | let run = co.wrap(function* () {
29 | if (functions.length == 0) {
30 | console.log("fetching relevant functions...");
31 |
32 | functions = yield listFunctions();
33 | console.log(`found ${functions.length} functions`);
34 | }
35 |
36 | console.log("invoking $LATEST...");
37 | for (let func of functions) {
38 | yield Lambda.invoke({
39 | FunctionName: func,
40 | InvocationType: "Event"
41 | }).promise();
42 | }
43 | });
44 |
45 | run();
--------------------------------------------------------------------------------
/java/.npmignore:
--------------------------------------------------------------------------------
1 | *.class
2 | target
3 | /bin/
4 | /.settings/
5 | .project
6 | .classpath
7 |
8 | # Package Files
9 | *.jar
10 | *.war
11 | *.ear
12 |
13 | # Serverless directories
14 | .serverless
--------------------------------------------------------------------------------
/java/hello.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/java/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | com.serverless
5 | hello
6 | jar
7 | dev
8 | hello
9 |
10 |
11 | 1.8
12 | 1.8
13 | UTF-8
14 |
15 |
16 |
17 |
18 | com.amazonaws
19 | aws-lambda-java-core
20 | 1.1.0
21 |
22 |
23 | com.amazonaws
24 | aws-lambda-java-log4j
25 | 1.0.0
26 |
27 |
28 | com.fasterxml.jackson.core
29 | jackson-core
30 | 2.8.5
31 |
32 |
33 | com.fasterxml.jackson.core
34 | jackson-databind
35 | 2.8.5
36 |
37 |
38 | com.fasterxml.jackson.core
39 | jackson-annotations
40 | 2.8.5
41 |
42 |
43 |
44 |
45 |
46 |
55 |
56 | org.apache.maven.plugins
57 | maven-shade-plugin
58 | 2.3
59 |
60 | false
61 |
62 |
63 |
64 | package
65 |
66 | shade
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/java/serverless.yml:
--------------------------------------------------------------------------------
1 | service: aws-coldstart-java
2 |
3 | provider:
4 | name: aws
5 | runtime: java8
6 | versionFunctions: false
7 |
8 | package:
9 | artifact: target/hello-dev.jar
10 |
11 | functions:
12 | memory-128:
13 | handler: com.serverless.Handler
14 | memorySize: 128
15 |
16 | memory-256:
17 | handler: com.serverless.Handler
18 | memorySize: 256
19 |
20 | memory-512:
21 | handler: com.serverless.Handler
22 | memorySize: 512
23 |
24 | memory-1024:
25 | handler: com.serverless.Handler
26 | memorySize: 1024
27 |
28 | memory-1536:
29 | handler: com.serverless.Handler
30 | memorySize: 1536
--------------------------------------------------------------------------------
/java/src/main/java/com/serverless/ApiGatewayResponse.java:
--------------------------------------------------------------------------------
1 | package com.serverless;
2 |
3 | import java.nio.charset.StandardCharsets;
4 | import java.util.Base64;
5 | import java.util.Collections;
6 | import java.util.Map;
7 |
8 | import org.apache.log4j.Logger;
9 |
10 | import com.fasterxml.jackson.core.JsonProcessingException;
11 | import com.fasterxml.jackson.databind.ObjectMapper;
12 |
13 | public class ApiGatewayResponse {
14 |
15 | private final int statusCode;
16 | private final String body;
17 | private final Map headers;
18 | private final boolean isBase64Encoded;
19 |
20 | public ApiGatewayResponse(int statusCode, String body, Map headers, boolean isBase64Encoded) {
21 | this.statusCode = statusCode;
22 | this.body = body;
23 | this.headers = headers;
24 | this.isBase64Encoded = isBase64Encoded;
25 | }
26 |
27 | public int getStatusCode() {
28 | return statusCode;
29 | }
30 |
31 | public String getBody() {
32 | return body;
33 | }
34 |
35 | public Map getHeaders() {
36 | return headers;
37 | }
38 |
39 | // API Gateway expects the property to be called "isBase64Encoded" => isIs
40 | public boolean isIsBase64Encoded() {
41 | return isBase64Encoded;
42 | }
43 |
44 | public static Builder builder() {
45 | return new Builder();
46 | }
47 |
48 | public static class Builder {
49 |
50 | private static final Logger LOG = Logger.getLogger(ApiGatewayResponse.Builder.class);
51 |
52 | private static final ObjectMapper objectMapper = new ObjectMapper();
53 |
54 | private int statusCode = 200;
55 | private Map headers = Collections.emptyMap();
56 | private String rawBody;
57 | private Object objectBody;
58 | private byte[] binaryBody;
59 | private boolean base64Encoded;
60 |
61 | public Builder setStatusCode(int statusCode) {
62 | this.statusCode = statusCode;
63 | return this;
64 | }
65 |
66 | public Builder setHeaders(Map headers) {
67 | this.headers = headers;
68 | return this;
69 | }
70 |
71 | /**
72 | * Builds the {@link ApiGatewayResponse} using the passed raw body string.
73 | */
74 | public Builder setRawBody(String rawBody) {
75 | this.rawBody = rawBody;
76 | return this;
77 | }
78 |
79 | /**
80 | * Builds the {@link ApiGatewayResponse} using the passed object body
81 | * converted to JSON.
82 | */
83 | public Builder setObjectBody(Object objectBody) {
84 | this.objectBody = objectBody;
85 | return this;
86 | }
87 |
88 | /**
89 | * Builds the {@link ApiGatewayResponse} using the passed binary body
90 | * encoded as base64. {@link #setBase64Encoded(boolean)
91 | * setBase64Encoded(true)} will be in invoked automatically.
92 | */
93 | public Builder setBinaryBody(byte[] binaryBody) {
94 | this.binaryBody = binaryBody;
95 | setBase64Encoded(true);
96 | return this;
97 | }
98 |
99 | /**
100 | * A binary or rather a base64encoded responses requires
101 | *
102 | * - "Binary Media Types" to be configured in API Gateway
103 | *
- a request with an "Accept" header set to one of the "Binary Media
104 | * Types"
105 | *
106 | */
107 | public Builder setBase64Encoded(boolean base64Encoded) {
108 | this.base64Encoded = base64Encoded;
109 | return this;
110 | }
111 |
112 | public ApiGatewayResponse build() {
113 | String body = null;
114 | if (rawBody != null) {
115 | body = rawBody;
116 | } else if (objectBody != null) {
117 | try {
118 | body = objectMapper.writeValueAsString(objectBody);
119 | } catch (JsonProcessingException e) {
120 | LOG.error("failed to serialize object", e);
121 | throw new RuntimeException(e);
122 | }
123 | } else if (binaryBody != null) {
124 | body = new String(Base64.getEncoder().encode(binaryBody), StandardCharsets.UTF_8);
125 | }
126 | return new ApiGatewayResponse(statusCode, body, headers, base64Encoded);
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/java/src/main/java/com/serverless/Handler.java:
--------------------------------------------------------------------------------
1 | package com.serverless;
2 |
3 | import java.util.Map;
4 |
5 | import com.amazonaws.services.lambda.runtime.Context;
6 | import com.amazonaws.services.lambda.runtime.RequestHandler;
7 |
8 | public class Handler implements RequestHandler