├── .gitignore ├── LICENSE.txt ├── MiniCommandLineHelper ├── CmdHelper.cs ├── CustomAttributes.cs ├── MiniCommandLineHelper.csproj ├── Properties │ └── AssemblyInfo.cs ├── TestCategories.cs └── Utility.cs ├── README.md ├── SECURITY.md ├── SampleUsages ├── App.config ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── SampleUsages.csproj ├── TestSamples │ ├── Blob-NodeJs-CPUIntensive │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── Blob-NodeJs-HighMemory │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── Blob-NodeJs-LowUsage │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── Http-NodeJs-CPUIntensive │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── Http-NodeJs-HighMemory │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── Http-NodeJs-LowUsage │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── Queue-NodeJs-CPUIntensive │ │ ├── azuredep.json │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── Queue-NodeJs-HighMemory │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── Queue-NodeJs-LowUsage │ │ ├── azuredeploy.json │ │ ├── function.json │ │ └── index.js │ ├── README.html │ └── README.md └── packages.config ├── ServerlessBenchmark.sln ├── ServerlessBenchmark ├── App.config ├── Constants.cs ├── LoadProfiles │ ├── LinearLoad.cs │ └── TriggerTestLoadProfile.cs ├── MetricInfo │ ├── Metric.cs │ └── PerfMetrics.cs ├── PerfResultProviders │ ├── AwsGenericPerformanceResultsProvider.cs │ ├── AwsPerformanceResultProviderBase.cs │ ├── AzureGenericPerformanceResultsProvider.cs │ ├── AzurePerformanceResultProviderBase.cs │ ├── FunctionLogs.cs │ └── PerfResultProvider.cs ├── PerfTestResult.cs ├── Properties │ └── AssemblyInfo.cs ├── ServerlessBenchmark.csproj ├── ServerlessPlatformControllers │ ├── AWS │ │ ├── AWS_CloudPlatformResponse.cs │ │ └── AWS_Controller.cs │ ├── Azure │ │ └── AzureController.cs │ ├── CloudPlatformController.cs │ ├── CloudPlatformRequest.cs │ └── CloudPlatformResponse.cs ├── SupplementalPerfTestResult.cs ├── TestRequest.cs ├── TriggerTests │ ├── AWS │ │ ├── AmazonApiGatewayTriggerTest.cs │ │ ├── AmazonS3TriggerTest.cs │ │ ├── AmazonSnsToSqs.cs │ │ └── AmazonSqsTriggerTest.cs │ ├── Azure │ │ ├── AzureBlobTriggerTest.cs │ │ ├── AzureHttpTriggerTest.cs │ │ └── AzureQueueTriggerTest.cs │ └── BaseTriggers │ │ ├── BlobTriggerTest.cs │ │ ├── FunctionTest.cs │ │ ├── HttpTriggerTest.cs │ │ ├── QueueTriggerTest.cs │ │ └── StorageTriggerTest.cs ├── Utility.cs └── packages.config └── ServerlessTestOrchestrator ├── App.config ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── ServerlessTestOrchestrator.csproj ├── TestDescription.cs ├── TestScenarioOrchestrator.cs └── TestScenarios ├── AzureBlobTestScenario.cs └── ITestScenario.cs /.gitignore: -------------------------------------------------------------------------------- 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 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | *.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.pfx 193 | *.publishsettings 194 | node_modules/ 195 | orleans.codegen.cs 196 | 197 | # Since there are multiple workflows, uncomment next line to ignore bower_components 198 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 199 | #bower_components/ 200 | 201 | # RIA/Silverlight projects 202 | Generated_Code/ 203 | 204 | # Backup & report files from converting an old project file 205 | # to a newer Visual Studio version. Backup files are not needed, 206 | # because we have git ;-) 207 | _UpgradeReport_Files/ 208 | Backup*/ 209 | UpgradeLog*.XML 210 | UpgradeLog*.htm 211 | 212 | # SQL Server files 213 | *.mdf 214 | *.ldf 215 | 216 | # Business Intelligence projects 217 | *.rdl.data 218 | *.bim.layout 219 | *.bim_*.settings 220 | 221 | # Microsoft Fakes 222 | FakesAssemblies/ 223 | 224 | # GhostDoc plugin setting file 225 | *.GhostDoc.xml 226 | 227 | # Node.js Tools for Visual Studio 228 | .ntvs_analysis.dat 229 | 230 | # Visual Studio 6 build log 231 | *.plg 232 | 233 | # Visual Studio 6 workspace options file 234 | *.opt 235 | 236 | # Visual Studio LightSwitch build output 237 | **/*.HTMLClient/GeneratedArtifacts 238 | **/*.DesktopClient/GeneratedArtifacts 239 | **/*.DesktopClient/ModelManifest.xml 240 | **/*.Server/GeneratedArtifacts 241 | **/*.Server/ModelManifest.xml 242 | _Pvt_Extensions 243 | 244 | # Paket dependency manager 245 | .paket/paket.exe 246 | paket-files/ 247 | 248 | # FAKE - F# Make 249 | .fake/ 250 | 251 | # JetBrains Rider 252 | .idea/ 253 | *.sln.iml 254 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation. All rights reserved. 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /MiniCommandLineHelper/CmdHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | 7 | namespace MiniCommandLineHelper 8 | { 9 | public abstract class CmdHelper 10 | { 11 | private ConsoleColor _originalConsoleColor; 12 | public void Main(string[] args) 13 | { 14 | if (args.Any((arg) => arg.Equals("-h", StringComparison.CurrentCultureIgnoreCase)) || args.Length == 0) 15 | { 16 | Help(); 17 | return; 18 | } 19 | RunCommand(args); 20 | } 21 | 22 | //protected abstract Assembly ExecutingAssembly { get; } 23 | 24 | protected void RunCommand(string[] args) 25 | { 26 | _originalConsoleColor = Console.ForegroundColor; 27 | MethodInfo methodInfo = null; 28 | 29 | try 30 | { 31 | var command = args[0]; 32 | var userCommandArgs = args.Skip(1).ToArray(); 33 | 34 | var assembly = Assembly.GetEntryAssembly(); 35 | var mainProgram = (from type in assembly.GetTypes() where type.Name == "Program" select type).First(); 36 | methodInfo = 37 | mainProgram.GetMethods() 38 | .First( 39 | method => 40 | method.Name.ToLower() == command.ToLower() && 41 | method.IsDefined(typeof (CommandAttribute))); 42 | 43 | var commandArgs = Utility.CombineParameters(userCommandArgs, methodInfo.GetParameters()); 44 | methodInfo.Invoke(this, commandArgs); 45 | } 46 | catch (IndexOutOfRangeException) 47 | { 48 | Help(); 49 | } 50 | catch (Exception ex) 51 | { 52 | Console.ForegroundColor = _originalConsoleColor; 53 | Console.WriteLine("Exiting benchmark"); 54 | } 55 | } 56 | 57 | private void WriteMethodData(MethodInfo methodInfo) 58 | { 59 | if (methodInfo == null) 60 | { 61 | Console.WriteLine("Method unknown. Allowed methods: {0}", Environment.NewLine); 62 | Help(); 63 | } 64 | else 65 | { 66 | Help(methodInfo); 67 | } 68 | } 69 | 70 | protected void Help() 71 | { 72 | var assembly = Assembly.GetEntryAssembly(); 73 | 74 | //print out all StressCommands 75 | var methods = from type in assembly.GetTypes() 76 | where type.Name == "Program" 77 | from method in type.GetMethods() 78 | where 79 | Attribute.IsDefined(method, typeof(CommandAttribute)) 80 | select method; 81 | 82 | 83 | foreach (var method in methods) 84 | { 85 | var methodInfoParsed = GetMethodInfoParsed(method); 86 | Console.WriteLine(methodInfoParsed); 87 | Console.WriteLine(); 88 | } 89 | } 90 | 91 | protected void Help(MethodInfo method) 92 | { 93 | if (Attribute.IsDefined(method, typeof (CommandAttribute))) 94 | { 95 | Console.WriteLine(GetMethodInfoParsed(method)); 96 | Console.WriteLine(); 97 | } 98 | } 99 | 100 | private string GetMethodInfoParsed(MethodInfo method) 101 | { 102 | var info = new StringBuilder(); 103 | var methodName = method.Name; 104 | var parameters = method.GetParameters(); 105 | 106 | info.Append(" "); 107 | info.Append(methodName); 108 | info.Append(" "); 109 | 110 | foreach (var param in parameters) 111 | { 112 | var paramInfo = string.Empty; 113 | 114 | if (param.HasDefaultValue) 115 | { 116 | paramInfo = string.Format( 117 | "[-{0}:<{1}>:{2}]", 118 | param.Name, 119 | GetTypeInfo(param.ParameterType), 120 | param.DefaultValue); 121 | } 122 | else 123 | { 124 | paramInfo = string.Format( 125 | "<{0}:{1}>", 126 | param.Name, 127 | GetTypeInfo(param.ParameterType)); 128 | } 129 | 130 | info.Append(paramInfo); 131 | info.Append(" "); 132 | } 133 | 134 | return info.ToString(); 135 | } 136 | 137 | private string GetTypeInfo(Type type) 138 | { 139 | if (!type.IsEnum) 140 | { 141 | return type.Name; 142 | } 143 | else 144 | { 145 | return string.Join("|", Enum.GetNames(type)); 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /MiniCommandLineHelper/CustomAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MiniCommandLineHelper 4 | { 5 | /// 6 | /// Attribute used for organizing the Help message 7 | /// 8 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] 9 | public class CommandLineAttribute : Attribute 10 | { 11 | private readonly string _commandLineHelp; 12 | 13 | public string Help 14 | { 15 | get { return _commandLineHelp; } 16 | } 17 | 18 | public CommandLineAttribute(string commandLineHelp) 19 | { 20 | _commandLineHelp = commandLineHelp; 21 | } 22 | } 23 | 24 | /// 25 | /// Group a test case into a category 26 | /// 27 | [AttributeUsage(AttributeTargets.All)] 28 | public class TestCategoryAttribute : Attribute 29 | { 30 | private readonly TestCategories _category; 31 | 32 | public TestCategories TestCategory 33 | { 34 | get { return _category;} 35 | } 36 | 37 | public TestCategoryAttribute(TestCategories category) 38 | { 39 | _category = category; 40 | } 41 | } 42 | 43 | /// 44 | /// A specific test 45 | /// 46 | [AttributeUsage(AttributeTargets.Method)] 47 | public class AntaresTest : Attribute 48 | { 49 | 50 | } 51 | 52 | /// 53 | /// Command 54 | /// 55 | [AttributeUsage(AttributeTargets.Method)] 56 | public class CommandAttribute : Attribute 57 | { 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /MiniCommandLineHelper/MiniCommandLineHelper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {600BA962-07EA-46EC-B8F5-9BC5933C5533} 8 | Library 9 | Properties 10 | MiniCommandLineHelper 11 | MiniCommandLineHelper 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 56 | -------------------------------------------------------------------------------- /MiniCommandLineHelper/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MiniCommandLineHelper")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MiniCommandLineHelper")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("062cc2a3-470e-4266-bc1c-4eb671d63ef6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MiniCommandLineHelper/TestCategories.cs: -------------------------------------------------------------------------------- 1 | namespace MiniCommandLineHelper 2 | { 3 | public enum TestCategories 4 | { 5 | ColdSite, 6 | GeoMaster 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /MiniCommandLineHelper/Utility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace MiniCommandLineHelper 7 | { 8 | public enum StressPipelineOperation 9 | { 10 | Start, 11 | Creation, 12 | Publish, 13 | Load, 14 | Deletion, 15 | FundamentalReport 16 | } 17 | 18 | public static class Utility 19 | { 20 | /// 21 | /// Consolidate user parameters and default parameters 22 | /// 23 | /// 24 | /// 25 | /// 26 | public static object[] CombineParameters(string[] userArgs, ParameterInfo[] methodParameters) 27 | { 28 | var joinedArgs = new List(); 29 | var tempUserArgs = new Dictionary(); 30 | int i = 0; 31 | try 32 | { 33 | if (userArgs.Length > 0) 34 | { 35 | foreach (var tmp in userArgs) 36 | { 37 | if (tmp.StartsWith("-")) 38 | { 39 | var paramAndValue = new[] {tmp.Substring(1, tmp.IndexOf(":", StringComparison.Ordinal) - 1), tmp.Substring(tmp.IndexOf(":", StringComparison.Ordinal) + 1)}; 40 | tempUserArgs.Add(paramAndValue[0].ToLower(), paramAndValue[1]); 41 | } 42 | else 43 | { 44 | tempUserArgs.Add(methodParameters[i].Name.ToLower(), tmp); 45 | } 46 | i++; 47 | } 48 | } 49 | foreach (var parameter in methodParameters) 50 | { 51 | var val = parameter.DefaultValue; 52 | var key = parameter.Name.ToLower(); 53 | if (tempUserArgs.ContainsKey(key)) 54 | { 55 | val = tempUserArgs[key]; 56 | } 57 | Type paramType = parameter.ParameterType; 58 | 59 | try 60 | { 61 | val = Convert.ChangeType(val, paramType); 62 | } 63 | catch (InvalidCastException) 64 | { 65 | if (paramType.IsEnum) 66 | { 67 | var enumValues = Enum.GetNames(paramType); 68 | var constant = enumValues.FirstOrDefault(s => s.Equals(val.ToString(), StringComparison.CurrentCultureIgnoreCase)); 69 | if (constant != null) 70 | { 71 | val = Enum.Parse(paramType, constant); 72 | } 73 | else 74 | { 75 | var message = string.Format("Parameter {0} has unavailable value {1}! Available values are: {2}.", 76 | parameter.Name, 77 | val, 78 | string.Join("|", enumValues)); 79 | throw new ArgumentException(message); 80 | } 81 | } 82 | } 83 | 84 | joinedArgs.Add(val); 85 | } 86 | } 87 | catch (IndexOutOfRangeException) 88 | { 89 | throw new Exception("Not enough arguments"); 90 | } 91 | 92 | return joinedArgs.ToArray(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # azure-functions-performance-test 2 | 3 | ## Set up Environment 4 | 5 | ### Tests samples required to run the according tests. 6 | 7 | #### Queue-Node-Js-CPU-Intensive 8 | 9 |

10 | Function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size 11 | then in multiplies matrixes, prints "Finish." when calculation is done. 12 | This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower 13 |

14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | #### Queue-Node-Js-High-Memory 24 | 25 |

26 | Function is designed to allocate big array depending on input size. 27 |

28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | #### Queue-Node-Js-Low-Usage 38 | 39 |

40 | Function has low usage gets message, reads it count to 1000 and finishes. 41 |

42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | #### Blob-Node-Js-CPU-Intensive 53 | 54 |

55 | Function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size 56 | then in multiplies matrixes, prints "Finish." when calculation is done. 57 | This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower 58 |

59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | #### Blob-Node-Js-High-Memory 69 | 70 |

71 | Function is designed to allocate big array depending on input size. 72 |

73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | #### Blob-Node-Js-Low-Usage 83 | 84 |

85 | Function has low usage gets message, reads it count to 1000 and finishes. 86 |

87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | #### Http-Node-Js-CPU-Intensive 99 | 100 |

101 | Function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size 102 | then in multiplies matrixes, prints "Finish." when calculation is done. 103 | This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower 104 |

105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | #### Http-Node-Js-High-Memory 115 | 116 |

117 | Function is designed to allocate big array depending on input size. 118 |

119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | #### Http-Node-Js-Low-Usage 129 | 130 |

131 | Function has low usage gets message, reads it count to 1000 and finishes. 132 |

133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SampleUsages/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SampleUsages/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Drawing; 5 | using System.IO; 6 | using System.Linq; 7 | using MiniCommandLineHelper; 8 | using ServerlessBenchmark; 9 | using ServerlessBenchmark.LoadProfiles; 10 | using ServerlessBenchmark.PerfResultProviders; 11 | using ServerlessBenchmark.TriggerTests.AWS; 12 | using ServerlessBenchmark.TriggerTests.Azure; 13 | using ServerlessBenchmark.TriggerTests.BaseTriggers; 14 | 15 | namespace SampleUsages 16 | { 17 | public class Program : CmdHelper 18 | { 19 | public new static void Main(string[] args) 20 | { 21 | var p = new Program(); 22 | ((CmdHelper) p).Main(args); 23 | } 24 | 25 | #region LambdaTests 26 | [Command] 27 | public void S3Test(string functionName, string blobPath, string srcBucket, string targetBucket, string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 28 | { 29 | var blobs = Directory.GetFiles(blobPath); 30 | var test = new AmazonS3TriggerTest(functionName, blobs, srcBucket, targetBucket); 31 | StorageTriggerTest(test, blobs, loadProfile, eps, repeat, durationMinutes); 32 | } 33 | 34 | [Command] 35 | public void SqsTest(string functionName, string messages, string srcQueue, string targetQueue, 36 | string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 37 | { 38 | var queueMessages = File.ReadAllLines(messages); 39 | var test = new AmazonSqsTriggerTest(functionName, queueMessages, srcQueue, targetQueue); 40 | StorageTriggerTest(test, queueMessages, loadProfile, eps, repeat, durationMinutes); 41 | } 42 | 43 | [Command] 44 | public void ApiGatewayTest(string functionName, string urlsFile, string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 45 | { 46 | var urls = File.ReadAllLines(urlsFile); 47 | var test = new AmazonApiGatewayTriggerTest(functionName, urls); 48 | HttpTriggerTest(test, urls, loadProfile, eps, repeat, durationMinutes); 49 | } 50 | 51 | [Command] 52 | public void SnsToSqsTest(string functionName, string messages, string srcTopic, string targetQueue, 53 | string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 54 | { 55 | var queueMessages = File.ReadAllLines(messages); 56 | var test = new AmazonSnsToSqs(functionName, queueMessages, srcTopic, targetQueue); 57 | StorageTriggerTest(test, queueMessages, loadProfile, eps, repeat, durationMinutes); 58 | } 59 | 60 | [Command] 61 | public void AnalyzeAwsTest(string functionName, DateTime startTime, DateTime endTime) 62 | { 63 | var resultsProvider = new AwsGenericPerformanceResultsProvider(); 64 | var results = resultsProvider.GetPerfMetrics(functionName, startTime, endTime); 65 | //print perf results 66 | var originalColor = Console.ForegroundColor; 67 | Console.ForegroundColor = ConsoleColor.Green; 68 | Console.WriteLine(results); 69 | Console.ForegroundColor = originalColor; 70 | } 71 | #endregion 72 | 73 | #region AzureFunctionTest 74 | 75 | [Command] 76 | public void BlobTest(string functionName, string blobPath, string srcBlobContainer, 77 | string targetBlobContainer, string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 78 | { 79 | AzureStorageTest(TriggerTypes.Blob, functionName, blobPath, srcBlobContainer, targetBlobContainer, loadProfile, eps, repeat, durationMinutes); 80 | } 81 | 82 | [Command] 83 | public void QueueTest(string functionName, string queueItems, string srcQueue, 84 | string targetQueue, string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 85 | { 86 | AzureStorageTest(TriggerTypes.Queue, functionName, queueItems, srcQueue, targetQueue, loadProfile, eps, repeat, durationMinutes); 87 | } 88 | 89 | [Command] 90 | public void AzureHttpTest(string functionName, string urlsFile, string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 91 | { 92 | var urls = File.ReadAllLines(urlsFile); 93 | var test = new AzureHttpTriggerTest(functionName, urls); 94 | HttpTriggerTest(test, urls, loadProfile, eps, repeat, durationMinutes); 95 | } 96 | 97 | private void AzureStorageTest(TriggerTypes triggerType, string functionName, string items, string source, string target, string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 98 | { 99 | FunctionTest test; 100 | switch (triggerType) 101 | { 102 | case TriggerTypes.Blob: 103 | var blobs = Directory.GetFiles(items); 104 | test = new AzureBlobTriggerTest(functionName, blobs, source, target); 105 | StorageTriggerTest(test, blobs, loadProfile, eps, repeat, durationMinutes); 106 | break; 107 | case TriggerTypes.Queue: 108 | var queueMessages = File.ReadAllLines(items); 109 | test = new AzureQueueTriggerTest(functionName, queueMessages, source, target); 110 | StorageTriggerTest(test, queueMessages, loadProfile, eps, repeat, durationMinutes); 111 | break; 112 | } 113 | } 114 | 115 | [Command] 116 | public void AnalyzeAzureTest(string functionName, DateTime startTime, DateTime endTime) 117 | { 118 | var resultsProvider = new AzureGenericPerformanceResultsProvider(); 119 | var results = resultsProvider.GetPerfMetrics(functionName, startTime, endTime); 120 | //print perf results 121 | var originalColor = Console.ForegroundColor; 122 | Console.ForegroundColor = ConsoleColor.Green; 123 | Console.WriteLine(results); 124 | Console.ForegroundColor = originalColor; 125 | } 126 | #endregion 127 | 128 | private void HttpTriggerTest(FunctionTest functionTest, IEnumerable urls, string loadProfile, int eps = 0, bool repeat = false, 129 | int durationMinutes = 0) 130 | { 131 | TriggerTestLoadProfile profile; 132 | if (loadProfile.Equals("Linear", StringComparison.CurrentCultureIgnoreCase) && repeat) 133 | { 134 | if (durationMinutes <= 0) 135 | { 136 | throw new ArgumentException("No parameter to specify how long to repeat this load. Indicate how long in minutes to repeat load.", "durationMinutes"); 137 | } 138 | profile = new LinearLoad(TimeSpan.FromMinutes(durationMinutes), eps == 0 ? 1 : eps); 139 | } 140 | else if (loadProfile.Equals("Linear", StringComparison.CurrentCultureIgnoreCase) && !repeat) 141 | { 142 | profile = new LinearLoad(urls.Count(), eps == 0 ? 1 : eps); 143 | } 144 | else 145 | { 146 | throw new Exception(string.Format("{0} does not exist", loadProfile)); 147 | } 148 | var perfResult = functionTest.RunAsync(profile).Result; 149 | 150 | //print perf results 151 | var originalColor = Console.ForegroundColor; 152 | Console.ForegroundColor = ConsoleColor.Green; 153 | Console.WriteLine(perfResult); 154 | Console.ForegroundColor = originalColor; 155 | } 156 | 157 | private void StorageTriggerTest(FunctionTest functionTest, IEnumerable sourceItems, string loadProfile, int eps = 0, bool repeat = false, int durationMinutes = 0) 158 | { 159 | TriggerTestLoadProfile profile; 160 | 161 | if (loadProfile.Equals("Linear", StringComparison.CurrentCultureIgnoreCase) && repeat) 162 | { 163 | if (durationMinutes <= 0) 164 | { 165 | throw new ArgumentException("No parameter to specify how long to repeat this load. Indicate how long in minutes to repeat load.", "durationMinutes"); 166 | } 167 | profile = new LinearLoad(TimeSpan.FromMinutes(durationMinutes), eps == 0 ? 1 : eps); 168 | } 169 | else if (loadProfile.Equals("Linear", StringComparison.CurrentCultureIgnoreCase) && !repeat) 170 | { 171 | profile = new LinearLoad(sourceItems.Count(), eps == 0 ? 1 : eps); 172 | } 173 | else 174 | { 175 | throw new Exception(string.Format("{0} does not exist", loadProfile)); 176 | } 177 | 178 | var perfResult = functionTest.RunAsync(profile).Result; 179 | 180 | //print perf results 181 | var originalColor = Console.ForegroundColor; 182 | Console.ForegroundColor = ConsoleColor.Green; 183 | Console.WriteLine(perfResult); 184 | Console.ForegroundColor = originalColor; 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /SampleUsages/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SampleUsages")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SampleUsages")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("834f2f93-ce2f-4080-b4e0-49aee23c4617")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SampleUsages/SampleUsages.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6B65B2D7-6344-4B15-A428-483E74E9AF51} 8 | Exe 9 | Properties 10 | SampleUsages 11 | SampleUsages 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | {600ba962-07ea-46ec-b8f5-9bc5933c5533} 75 | MiniCommandLineHelper 76 | 77 | 78 | {582cc16b-6c75-494b-b27f-7a769dec0c30} 79 | ServerlessBenchmark 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 102 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-CPUIntensive/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": 80 | { 81 | "index.js": "// function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size\r\n// then in multiplies matrixes, prints \"Finish.\" when calculation is done.\r\n// This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower\r\n\r\nmodule.exports = function (context, myBlob) {\r\n main(context, myBlob);\r\n context.done();\r\n}\r\n\r\nvar multiple_row_and_column = function(row, column){\r\n // assume same length of row and column\r\n var result = 0;\r\n for(var i = 0; i < row.length; i++)\r\n {\r\n result += row[i] * column[i];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nvar create_random_matrix = function(size, seed, value_min, value_max) {\r\n var matrix = [];\r\n\r\n for (var i = 0; i < size; i++) {\r\n var row = [];\r\n for (var j = 0; j < size; j++){\r\n var val = parseInt(Math.random(seed) * (value_max - value_min), 10);\r\n row.push(val);\r\n }\r\n\r\n matrix.push(row);\r\n }\r\n\r\n return matrix;\r\n}\r\n\r\nvar get_row_from_matrix = function(matrix, i){\r\n return matrix[i];\r\n}\r\n\r\nvar get_column_from_matrix = function(matrix, j){\r\n var column = [];\r\n for(var i = 0; i < matrix.length; i++){\r\n column.push(matrix[i][j]);\r\n }\r\n\r\n return column;\r\n}\r\n\r\nvar multiple_matrix = function(matrixA, matrixB) {\r\n var result = [];\r\n\r\n for (var i = 0; i < matrixA.length; i++) {\r\n var result_row = [];\r\n for (var j = 0; j < matrixA[0].length; j++) {\r\n var row = get_row_from_matrix(matrixA, i);\r\n var column = get_column_from_matrix(matrixB, j);\r\n result_row.push(multiple_row_and_column(row, column));\r\n }\r\n result.push(result_row);\r\n }\r\n\r\n return result; \r\n}\r\n\r\nvar print_matrix = function(matrix){\r\n for (var i = 0; i < matrix.length; i++) {\r\n var row = '';\r\n for (var j = 0; j < matrix[0].length; j++) {\r\n row += (' ' + matrix[i][j]);\r\n }\r\n\r\n console.log(row);\r\n }\r\n}\r\n\r\nvar main = function (context, myBlob) {\r\n var seed = 123;\r\n var value_min = 0;\r\n var value_max = 101;\r\n var size = parseInt(myBlob);\r\n\r\n var matrix = create_random_matrix(size, seed, value_min, value_max);\r\n seed = 2 * seed;\r\n var matrix2 = create_random_matrix(size, seed, value_min, value_max);\r\n multiple_matrix(matrix, matrix2);\r\n}\r\n" 82 | }, 83 | "config": { 84 | "bindings": [ 85 | { 86 | "type": "blobTrigger", 87 | "name": "myBlob", 88 | "path": "mycontainer/{name}", 89 | "direction": "in" 90 | }, 91 | { 92 | "type": "blobTrigger", 93 | "name": "myQueue", 94 | "path": "myresultcontainer/{name}", 95 | "direction": "out" 96 | } 97 | ] 98 | } 99 | } 100 | } 101 | ], 102 | "type": "Microsoft.Web/sites" 103 | } 104 | ], 105 | "variables": { 106 | "functionAppName": "[concat('blob-nodejs-cpu-intensive', uniquestring(resourceGroup().id))]", 107 | "functionName": "function", 108 | "hostingPlanName": "[concat('blob-nodejs-cpu-intensive', uniquestring(resourceGroup().id))]", 109 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 110 | } 111 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-CPUIntensive/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "blobTrigger", 5 | "name": "myBlob", 6 | "path": "mycontainer/{name}", 7 | "direction": "in" 8 | }, 9 | { 10 | "type": "blobTrigger", 11 | "name": "myQueue", 12 | "path": "myresultcontainer/{name}", 13 | "direction": "out" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-CPUIntensive/index.js: -------------------------------------------------------------------------------- 1 | // function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size 2 | // then in multiplies matrixes, prints "Finish." when calculation is done. 3 | // This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower 4 | 5 | module.exports = function (context, myBlob) { 6 | main(context, myBlob); 7 | context.done(); 8 | } 9 | 10 | var multiple_row_and_column = function(row, column){ 11 | // assume same length of row and column 12 | var result = 0; 13 | for(var i = 0; i < row.length; i++) 14 | { 15 | result += row[i] * column[i]; 16 | } 17 | 18 | return result; 19 | } 20 | 21 | var create_random_matrix = function(size, seed, value_min, value_max) { 22 | var matrix = []; 23 | 24 | for (var i = 0; i < size; i++) { 25 | var row = []; 26 | for (var j = 0; j < size; j++){ 27 | var val = parseInt(Math.random(seed) * (value_max - value_min), 10); 28 | row.push(val); 29 | } 30 | 31 | matrix.push(row); 32 | } 33 | 34 | return matrix; 35 | } 36 | 37 | var get_row_from_matrix = function(matrix, i){ 38 | return matrix[i]; 39 | } 40 | 41 | var get_column_from_matrix = function(matrix, j){ 42 | var column = []; 43 | for(var i = 0; i < matrix.length; i++){ 44 | column.push(matrix[i][j]); 45 | } 46 | 47 | return column; 48 | } 49 | 50 | var multiple_matrix = function(matrixA, matrixB) { 51 | var result = []; 52 | 53 | for (var i = 0; i < matrixA.length; i++) { 54 | var result_row = []; 55 | for (var j = 0; j < matrixA[0].length; j++) { 56 | var row = get_row_from_matrix(matrixA, i); 57 | var column = get_column_from_matrix(matrixB, j); 58 | result_row.push(multiple_row_and_column(row, column)); 59 | } 60 | result.push(result_row); 61 | } 62 | 63 | return result; 64 | } 65 | 66 | var print_matrix = function(matrix){ 67 | for (var i = 0; i < matrix.length; i++) { 68 | var row = ''; 69 | for (var j = 0; j < matrix[0].length; j++) { 70 | row += (' ' + matrix[i][j]); 71 | } 72 | 73 | console.log(row); 74 | } 75 | } 76 | 77 | var main = function (context, myBlob) { 78 | var seed = 123; 79 | var value_min = 0; 80 | var value_max = 101; 81 | var size = parseInt(myBlob); 82 | 83 | var matrix = create_random_matrix(size, seed, value_min, value_max); 84 | seed = 2 * seed; 85 | var matrix2 = create_random_matrix(size, seed, value_min, value_max); 86 | multiple_matrix(matrix, matrix2); 87 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-HighMemory/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": { 80 | "index.js": "// function is designed to allocate big array depending on input size\r\n\r\nmodule.exports = function (context, myBlob) {\r\n var array = [];\r\n var size = parseInt(myBlob);\r\n var seed = size;\r\n\r\n for(var i = 0; i < size; i++){\r\n var x = Math.random(seed) * size;\r\n array.push(x);\r\n }\r\n\r\n for(var j = 1; j < size; j++){\r\n var y = Math.random(seed) * size;\r\n array[j] = array[j - 1] + y;\r\n }\r\n \r\n context.done();\r\n}\r\n" 81 | }, 82 | "config": { 83 | "bindings": [ 84 | { 85 | "type": "blobTrigger", 86 | "name": "myBlob", 87 | "path": "mycontainer/{name}", 88 | "direction": "in" 89 | }, 90 | { 91 | "type": "blobTrigger", 92 | "name": "myQueue", 93 | "path": "myresultcontainer/{name}", 94 | "direction": "out" 95 | } 96 | ] 97 | } 98 | } 99 | } 100 | ], 101 | "type": "Microsoft.Web/sites" 102 | } 103 | ], 104 | "variables": { 105 | "functionAppName": "[concat('blob-nodejs-memory-intensive', uniquestring(resourceGroup().id))]", 106 | "functionName": "function", 107 | "hostingPlanName": "[concat('blob-nodejs-memory-intensive', uniquestring(resourceGroup().id))]", 108 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 109 | } 110 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-HighMemory/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "name": "req", 6 | "authLevel": "function", 7 | "direction": "in" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-HighMemory/index.js: -------------------------------------------------------------------------------- 1 | // function is designed to allocate big array depending on input size 2 | 3 | module.exports = function (context, myBlob) { 4 | var array = []; 5 | var size = parseInt(myBlob); 6 | var seed = size; 7 | 8 | for(var i = 0; i < size; i++){ 9 | var x = Math.random(seed) * size; 10 | array.push(x); 11 | } 12 | 13 | for(var j = 1; j < size; j++){ 14 | var y = Math.random(seed) * size; 15 | array[j] = array[j - 1] + y; 16 | } 17 | 18 | context.done(); 19 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-LowUsage/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": { 80 | "index.js": "// function has low usage gets message, reads it count to 1000 and finishes\r\n\r\nmodule.exports = function (context, myBlob) {\r\n context.log(\"Function started with input \" + myBlob);\r\n\r\n for(var i = 0; i < 1000; i++){\r\n context.log(i);\r\n }\r\n \r\n context.done();\r\n}\r\n" 81 | }, 82 | "config": { 83 | "bindings": [ 84 | { 85 | "type": "blobTrigger", 86 | "name": "myBlob", 87 | "path": "mycontainer/{name}", 88 | "direction": "in" 89 | }, 90 | { 91 | "type": "blobTrigger", 92 | "name": "myQueue", 93 | "path": "myresultcontainer/{name}", 94 | "direction": "out" 95 | } 96 | ] 97 | } 98 | } 99 | } 100 | ], 101 | "type": "Microsoft.Web/sites" 102 | } 103 | ], 104 | "variables": { 105 | "functionAppName": "[concat('blob-nodejs-low-usage', uniquestring(resourceGroup().id))]", 106 | "functionName": "function", 107 | "hostingPlanName": "[concat('blob-nodejs-low-usage', uniquestring(resourceGroup().id))]", 108 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 109 | } 110 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-LowUsage/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "name": "req", 6 | "authLevel": "function", 7 | "direction": "in" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Blob-NodeJs-LowUsage/index.js: -------------------------------------------------------------------------------- 1 | // function has low usage gets message, reads it count to 1000 and finishes 2 | 3 | module.exports = function (context, myBlob) { 4 | context.log("Function started with input " + myBlob); 5 | 6 | for(var i = 0; i < 1000; i++){ 7 | context.log(i); 8 | } 9 | 10 | context.done(); 11 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-CPUIntensive/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": 80 | { 81 | "index.js": "// function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size\r\n// then in multiplies matrixes, prints \"Finish.\" when calculation is done.\r\n// This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower\r\n\r\nmodule.exports = function (context, req) {\r\n main(context, req);\r\n context.done();\r\n}\r\n\r\nvar multiple_row_and_column = function(row, column){\r\n // assume same length of row and column\r\n var result = 0;\r\n for(var i = 0; i < row.length; i++)\r\n {\r\n result += row[i] * column[i];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nvar create_random_matrix = function(size, seed, value_min, value_max) {\r\n var matrix = [];\r\n\r\n for (var i = 0; i < size; i++) {\r\n var row = [];\r\n for (var j = 0; j < size; j++){\r\n var val = parseInt(Math.random(seed) * (value_max - value_min), 10);\r\n row.push(val);\r\n }\r\n\r\n matrix.push(row);\r\n }\r\n\r\n return matrix;\r\n}\r\n\r\nvar get_row_from_matrix = function(matrix, i){\r\n return matrix[i];\r\n}\r\n\r\nvar get_column_from_matrix = function(matrix, j){\r\n var column = [];\r\n for(var i = 0; i < matrix.length; i++){\r\n column.push(matrix[i][j]);\r\n }\r\n\r\n return column;\r\n}\r\n\r\nvar multiple_matrix = function(matrixA, matrixB) {\r\n var result = [];\r\n\r\n for (var i = 0; i < matrixA.length; i++) {\r\n var result_row = [];\r\n for (var j = 0; j < matrixA[0].length; j++) {\r\n var row = get_row_from_matrix(matrixA, i);\r\n var column = get_column_from_matrix(matrixB, j);\r\n result_row.push(multiple_row_and_column(row, column));\r\n }\r\n result.push(result_row);\r\n }\r\n\r\n return result; \r\n}\r\n\r\nvar print_matrix = function(matrix){\r\n for (var i = 0; i < matrix.length; i++) {\r\n var row = '';\r\n for (var j = 0; j < matrix[0].length; j++) {\r\n row += (' ' + matrix[i][j]);\r\n }\r\n\r\n console.log(row);\r\n }\r\n}\r\n\r\nvar main = function (context, req) {\r\n var seed = 123;\r\n var value_min = 0;\r\n var value_max = 101;\r\n var size = parseInt(req.body);\r\n\r\n var matrix = create_random_matrix(size, seed, value_min, value_max);\r\n seed = 2 * seed;\r\n var matrix2 = create_random_matrix(size, seed, value_min, value_max);\r\n multiple_matrix(matrix, matrix2);\r\n}\r\n" 82 | }, 83 | "config": { 84 | "bindings": [ 85 | { 86 | "type": "httpTrigger", 87 | "name": "req", 88 | "authLevel": "function", 89 | "direction": "in" 90 | } 91 | ] 92 | } 93 | } 94 | } 95 | ], 96 | "type": "Microsoft.Web/sites" 97 | } 98 | ], 99 | "variables": { 100 | "functionAppName": "[concat('http-nodejs-cpu-intensive', uniquestring(resourceGroup().id))]", 101 | "functionName": "function", 102 | "hostingPlanName": "[concat('http-nodejs-cpu-intensive', uniquestring(resourceGroup().id))]", 103 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 104 | } 105 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-CPUIntensive/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "name": "req", 6 | "authLevel": "function", 7 | "direction": "in" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-CPUIntensive/index.js: -------------------------------------------------------------------------------- 1 | // function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size 2 | // then in multiplies matrixes, prints "Finish." when calculation is done. 3 | // This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower 4 | 5 | module.exports = function (context, req) { 6 | main(context, req); 7 | context.done(); 8 | } 9 | 10 | var multiple_row_and_column = function(row, column){ 11 | // assume same length of row and column 12 | var result = 0; 13 | for(var i = 0; i < row.length; i++) 14 | { 15 | result += row[i] * column[i]; 16 | } 17 | 18 | return result; 19 | } 20 | 21 | var create_random_matrix = function(size, seed, value_min, value_max) { 22 | var matrix = []; 23 | 24 | for (var i = 0; i < size; i++) { 25 | var row = []; 26 | for (var j = 0; j < size; j++){ 27 | var val = parseInt(Math.random(seed) * (value_max - value_min), 10); 28 | row.push(val); 29 | } 30 | 31 | matrix.push(row); 32 | } 33 | 34 | return matrix; 35 | } 36 | 37 | var get_row_from_matrix = function(matrix, i){ 38 | return matrix[i]; 39 | } 40 | 41 | var get_column_from_matrix = function(matrix, j){ 42 | var column = []; 43 | for(var i = 0; i < matrix.length; i++){ 44 | column.push(matrix[i][j]); 45 | } 46 | 47 | return column; 48 | } 49 | 50 | var multiple_matrix = function(matrixA, matrixB) { 51 | var result = []; 52 | 53 | for (var i = 0; i < matrixA.length; i++) { 54 | var result_row = []; 55 | for (var j = 0; j < matrixA[0].length; j++) { 56 | var row = get_row_from_matrix(matrixA, i); 57 | var column = get_column_from_matrix(matrixB, j); 58 | result_row.push(multiple_row_and_column(row, column)); 59 | } 60 | result.push(result_row); 61 | } 62 | 63 | return result; 64 | } 65 | 66 | var print_matrix = function(matrix){ 67 | for (var i = 0; i < matrix.length; i++) { 68 | var row = ''; 69 | for (var j = 0; j < matrix[0].length; j++) { 70 | row += (' ' + matrix[i][j]); 71 | } 72 | 73 | console.log(row); 74 | } 75 | } 76 | 77 | var main = function (context, req) { 78 | var seed = 123; 79 | var value_min = 0; 80 | var value_max = 101; 81 | var size = parseInt(req.body); 82 | 83 | var matrix = create_random_matrix(size, seed, value_min, value_max); 84 | seed = 2 * seed; 85 | var matrix2 = create_random_matrix(size, seed, value_min, value_max); 86 | multiple_matrix(matrix, matrix2); 87 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-HighMemory/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": { 80 | "index.js": "// function is designed to allocate big array depending on input size\r\n\r\nmodule.exports = function (context, req) {\r\n var array = [];\r\n var size = parseInt(req.body);\r\n var seed = size;\r\n\r\n for(var i = 0; i < size; i++){\r\n var x = Math.random(seed) * size;\r\n array.push(x);\r\n }\r\n\r\n for(var j = 1; j < size; j++){\r\n var y = Math.random(seed) * size;\r\n array[j] = array[j - 1] + y;\r\n }\r\n \r\n context.done();\r\n}\r\n" 81 | }, 82 | "config": { 83 | "bindings": [ 84 | { 85 | "type": "httpTrigger", 86 | "name": "req", 87 | "authLevel": "function", 88 | "direction": "in" 89 | } 90 | ] 91 | } 92 | } 93 | } 94 | ], 95 | "type": "Microsoft.Web/sites" 96 | } 97 | ], 98 | "variables": { 99 | "functionAppName": "[concat('http-nodejs-memory-intensive', uniquestring(resourceGroup().id))]", 100 | "functionName": "function", 101 | "hostingPlanName": "[concat('http-nodejs-memory-intensive', uniquestring(resourceGroup().id))]", 102 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 103 | } 104 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-HighMemory/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "name": "req", 6 | "authLevel": "function", 7 | "direction": "in" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-HighMemory/index.js: -------------------------------------------------------------------------------- 1 | // function is designed to allocate big array depending on input size 2 | 3 | module.exports = function (context, req) { 4 | var array = []; 5 | var size = parseInt(req.body); 6 | var seed = size; 7 | 8 | for(var i = 0; i < size; i++){ 9 | var x = Math.random(seed) * size; 10 | array.push(x); 11 | } 12 | 13 | for(var j = 1; j < size; j++){ 14 | var y = Math.random(seed) * size; 15 | array[j] = array[j - 1] + y; 16 | } 17 | 18 | context.done(); 19 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-LowUsage/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": { 80 | "index.js": "// function has low usage gets message, reads it count to 1000 and finishes\r\n\r\nmodule.exports = function (context, req) {\r\n context.log(\"Function started with input \" + req.rawBody);\r\n\r\n for(var i = 0; i < 1000; i++){\r\n context.log(i);\r\n }\r\n \r\n context.done();\r\n}\r\n" 81 | }, 82 | "config": { 83 | "bindings": [ 84 | { 85 | "type": "httpTrigger", 86 | "name": "req", 87 | "authLevel": "function", 88 | "direction": "in" 89 | } 90 | ] 91 | } 92 | } 93 | } 94 | ], 95 | "type": "Microsoft.Web/sites" 96 | } 97 | ], 98 | "variables": { 99 | "functionAppName": "[concat('http-nodejs-low-usage', uniquestring(resourceGroup().id))]", 100 | "functionName": "function", 101 | "hostingPlanName": "[concat('http-nodejs-low-usage', uniquestring(resourceGroup().id))]", 102 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 103 | } 104 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-LowUsage/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "httpTrigger", 5 | "name": "req", 6 | "authLevel": "function", 7 | "direction": "in" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Http-NodeJs-LowUsage/index.js: -------------------------------------------------------------------------------- 1 | // function has low usage gets message, reads it count to 1000 and finishes 2 | 3 | module.exports = function (context, req) { 4 | context.log("Function started with input " + req.rawBody); 5 | 6 | for(var i = 0; i < 1000; i++){ 7 | context.log(i); 8 | } 9 | 10 | context.done(); 11 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-CPUIntensive/azuredep.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "appName": { 6 | "type": "string", 7 | "metadata": { 8 | "description": "The name of the function app that you wish to create." 9 | } 10 | }, 11 | "storageAccountType": { 12 | "type": "string", 13 | "defaultValue": "Standard_LRS", 14 | "allowedValues": [ 15 | "Standard_LRS", 16 | "Standard_GRS", 17 | "Standard_ZRS", 18 | "Premium_LRS" 19 | ], 20 | "metadata": { 21 | "description": "Storage Account type" 22 | } 23 | } 24 | }, 25 | "variables": { 26 | "functionAppName": "[parameters('appName')]", 27 | "hostingPlanName": "[parameters('appName')]", 28 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 29 | }, 30 | "resources": [ 31 | { 32 | "type": "Microsoft.Storage/storageAccounts", 33 | "name": "[variables('storageAccountName')]", 34 | "apiVersion": "2015-06-15", 35 | "location": "[resourceGroup().location]", 36 | "properties": { 37 | "accountType": "[parameters('storageAccountType')]" 38 | } 39 | }, 40 | { 41 | "type": "Microsoft.Web/serverfarms", 42 | "apiVersion": "2015-04-01", 43 | "name": "[variables('hostingPlanName')]", 44 | "location": "[resourceGroup().location]", 45 | "properties": { 46 | "name": "[variables('hostingPlanName')]", 47 | "computeMode": "Dynamic", 48 | "sku": "Dynamic" 49 | } 50 | }, 51 | { 52 | "apiVersion": "2015-08-01", 53 | "type": "Microsoft.Web/sites", 54 | "name": "[variables('functionAppName')]", 55 | "location": "[resourceGroup().location]", 56 | "kind": "functionapp", 57 | "properties": { 58 | "name": "[variables('functionAppName')]", 59 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 60 | }, 61 | "dependsOn": [ 62 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 63 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 64 | ], 65 | "resources": [ 66 | { 67 | "apiVersion": "2016-03-01", 68 | "name": "appsettings", 69 | "type": "config", 70 | "dependsOn": [ 71 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 72 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 73 | ], 74 | "properties": { 75 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 76 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 77 | "FUNCTIONS_EXTENSION_VERSION": "latest" 78 | } 79 | } 80 | ] 81 | } 82 | ] 83 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-CPUIntensive/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": 80 | { 81 | "index.js": "// function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size\r\n// then in multiplies matrixes, prints \"Finish.\" when calculation is done.\r\n// This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower\r\n\r\nmodule.exports = function (context, input) {\r\n main(context, input);\r\n context.done();\r\n }\r\n \r\n var multiple_row_and_column = function(row, column){\r\n // assume same length of row and column\r\n var result = 0;\r\n for(var i = 0; i < row.length; i++)\r\n {\r\n result += row[i] * column[i];\r\n }\r\n \r\n return result;\r\n }\r\n \r\n var create_random_matrix = function(size, seed, value_min, value_max) {\r\n var matrix = [];\r\n \r\n for (var i = 0; i < size; i++) {\r\n var row = [];\r\n for (var j = 0; j < size; j++){\r\n var val = parseInt(Math.random(seed) * (value_max - value_min), 10);\r\n row.push(val);\r\n }\r\n \r\n matrix.push(row);\r\n }\r\n \r\n return matrix;\r\n }\r\n \r\n var get_row_from_matrix = function(matrix, i){\r\n return matrix[i];\r\n }\r\n \r\n var get_column_from_matrix = function(matrix, j){\r\n var column = [];\r\n for(var i = 0; i < matrix.length; i++){\r\n column.push(matrix[i][j]);\r\n }\r\n \r\n return column;\r\n }\r\n \r\n var multiple_matrix = function(matrixA, matrixB) {\r\n var result = [];\r\n \r\n for (var i = 0; i < matrixA.length; i++) {\r\n var result_row = [];\r\n for (var j = 0; j < matrixA[0].length; j++) {\r\n var row = get_row_from_matrix(matrixA, i);\r\n var column = get_column_from_matrix(matrixB, j);\r\n result_row.push(multiple_row_and_column(row, column));\r\n }\r\n result.push(result_row);\r\n }\r\n \r\n return result; \r\n }\r\n \r\n var print_matrix = function(matrix){\r\n for (var i = 0; i < matrix.length; i++) {\r\n var row = '';\r\n for (var j = 0; j < matrix[0].length; j++) {\r\n row += (' ' + matrix[i][j]);\r\n }\r\n \r\n console.log(row);\r\n }\r\n }\r\n \r\n var main = function(context, size) {\r\n var seed = 123;\r\n var value_min = 0;\r\n var value_max = 101;\r\n \r\n var matrix = create_random_matrix(size, seed, value_min, value_max);\r\n seed = 2 * seed;\r\n var matrix2 = create_random_matrix(size, seed, value_min, value_max);\r\n multiple_matrix(matrix, matrix2);\r\n }\r\n" 82 | }, 83 | "config": { 84 | "bindings": [ 85 | { 86 | "type": "queueTrigger", 87 | "name": "input", 88 | "direction": "in", 89 | "queueName": "samples-node-js-cpu-perf-test" 90 | }] 91 | } 92 | } 93 | } 94 | ], 95 | "type": "Microsoft.Web/sites" 96 | } 97 | ], 98 | "variables": { 99 | "functionAppName": "[concat('queue-nodejs-cpu-intensive', uniquestring(resourceGroup().id))]", 100 | "functionName": "function", 101 | "hostingPlanName": "[concat('queue-nodejs-cpu-intensive', uniquestring(resourceGroup().id))]", 102 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 103 | } 104 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-CPUIntensive/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "queueTrigger", 5 | "name": "input", 6 | "direction": "in", 7 | "queueName": "samples-node-js-cpu-perf-test", 8 | "connection": "" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-CPUIntensive/index.js: -------------------------------------------------------------------------------- 1 | // function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size 2 | // then in multiplies matrixes, prints "Finish." when calculation is done. 3 | // This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower 4 | 5 | module.exports = function (context, input) { 6 | main(context, input); 7 | context.done(); 8 | } 9 | 10 | var multiple_row_and_column = function(row, column){ 11 | // assume same length of row and column 12 | var result = 0; 13 | for(var i = 0; i < row.length; i++) 14 | { 15 | result += row[i] * column[i]; 16 | } 17 | 18 | return result; 19 | } 20 | 21 | var create_random_matrix = function(size, seed, value_min, value_max) { 22 | var matrix = []; 23 | 24 | for (var i = 0; i < size; i++) { 25 | var row = []; 26 | for (var j = 0; j < size; j++){ 27 | var val = parseInt(Math.random(seed) * (value_max - value_min), 10); 28 | row.push(val); 29 | } 30 | 31 | matrix.push(row); 32 | } 33 | 34 | return matrix; 35 | } 36 | 37 | var get_row_from_matrix = function(matrix, i){ 38 | return matrix[i]; 39 | } 40 | 41 | var get_column_from_matrix = function(matrix, j){ 42 | var column = []; 43 | for(var i = 0; i < matrix.length; i++){ 44 | column.push(matrix[i][j]); 45 | } 46 | 47 | return column; 48 | } 49 | 50 | var multiple_matrix = function(matrixA, matrixB) { 51 | var result = []; 52 | 53 | for (var i = 0; i < matrixA.length; i++) { 54 | var result_row = []; 55 | for (var j = 0; j < matrixA[0].length; j++) { 56 | var row = get_row_from_matrix(matrixA, i); 57 | var column = get_column_from_matrix(matrixB, j); 58 | result_row.push(multiple_row_and_column(row, column)); 59 | } 60 | result.push(result_row); 61 | } 62 | 63 | return result; 64 | } 65 | 66 | var print_matrix = function(matrix){ 67 | for (var i = 0; i < matrix.length; i++) { 68 | var row = ''; 69 | for (var j = 0; j < matrix[0].length; j++) { 70 | row += (' ' + matrix[i][j]); 71 | } 72 | 73 | console.log(row); 74 | } 75 | } 76 | 77 | var main = function(context, size) { 78 | var seed = 123; 79 | var value_min = 0; 80 | var value_max = 101; 81 | 82 | var matrix = create_random_matrix(size, seed, value_min, value_max); 83 | seed = 2 * seed; 84 | var matrix2 = create_random_matrix(size, seed, value_min, value_max); 85 | multiple_matrix(matrix, matrix2); 86 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-HighMemory/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": { 80 | "index.js": "// function is designed to allocate big array depending on input size\r\n\r\nmodule.exports = function (context, size) {\r\n var array = [];\r\n var seed = size;\r\n\r\n for(var i = 0; i < size; i++){\r\n var x = Math.random(seed) * size;\r\n array.push(x);\r\n }\r\n\r\n for(var j = 1; j < size; j++){\r\n var y = Math.random(seed) * size;\r\n array[j] = array[j - 1] + y;\r\n }\r\n \r\n context.done();\r\n}\r\n" 81 | }, 82 | "config": { 83 | "bindings": [ 84 | { 85 | "type": "queueTrigger", 86 | "name": "input", 87 | "direction": "in", 88 | "queueName": "samples-node-js-memory-perf-test" 89 | } 90 | ] 91 | } 92 | } 93 | } 94 | ], 95 | "type": "Microsoft.Web/sites" 96 | } 97 | ], 98 | "variables": { 99 | "functionAppName": "[concat('queue-nodejs-memory-intensive', uniquestring(resourceGroup().id))]", 100 | "functionName": "function", 101 | "hostingPlanName": "[concat('queue-nodejs-memory-intensive', uniquestring(resourceGroup().id))]", 102 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 103 | } 104 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-HighMemory/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "queueTrigger", 5 | "name": "input", 6 | "direction": "in", 7 | "queueName": "samples-node-js-memory-perf-test", 8 | "connection": "" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-HighMemory/index.js: -------------------------------------------------------------------------------- 1 | // function is designed to allocate big array depending on input size 2 | 3 | module.exports = function (context, size) { 4 | var array = []; 5 | var seed = size; 6 | 7 | for(var i = 0; i < size; i++){ 8 | var x = Math.random(seed) * size; 9 | array.push(x); 10 | } 11 | 12 | for(var j = 1; j < size; j++){ 13 | var y = Math.random(seed) * size; 14 | array[j] = array[j - 1] + y; 15 | } 16 | 17 | context.done(); 18 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-LowUsage/azuredeploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schemas.management.azure.com/schemas/2015-01-01-preview/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "storageAccountType": { 6 | "allowedValues": [ 7 | "Standard_LRS", 8 | "Standard_GRS", 9 | "Standard_ZRS", 10 | "Premium_LRS" 11 | ], 12 | "defaultValue": "Standard_LRS", 13 | "metadata": { 14 | "description": "Storage Account type" 15 | }, 16 | "type": "string" 17 | } 18 | }, 19 | "resources": [ 20 | { 21 | "apiVersion": "2015-06-15", 22 | "location": "[resourceGroup().location]", 23 | "name": "[variables('storageAccountName')]", 24 | "properties": { 25 | "accountType": "[parameters('storageAccountType')]" 26 | }, 27 | "type": "Microsoft.Storage/storageAccounts" 28 | }, 29 | { 30 | "apiVersion": "2015-04-01", 31 | "location": "[resourceGroup().location]", 32 | "name": "[variables('hostingPlanName')]", 33 | "properties": { 34 | "computeMode": "Dynamic", 35 | "name": "[variables('hostingPlanName')]", 36 | "sku": "Dynamic" 37 | }, 38 | "type": "Microsoft.Web/serverfarms" 39 | }, 40 | { 41 | "apiVersion": "2015-08-01", 42 | "dependsOn": [ 43 | "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", 44 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 45 | ], 46 | "kind": "functionapp", 47 | "location": "[resourceGroup().location]", 48 | "name": "[variables('functionAppName')]", 49 | "properties": { 50 | "name": "[variables('functionAppName')]", 51 | "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]" 52 | }, 53 | "resources": [ 54 | { 55 | "apiVersion": "2016-03-01", 56 | "dependsOn": [ 57 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 58 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 59 | ], 60 | "name": "appsettings", 61 | "properties": { 62 | "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING" : "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 63 | "WEBSITE_CONTENTSHARE" : "[concat(variables('functionAppName'))]", 64 | "AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 65 | "AzureWebJobsStorage": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1,';')]", 66 | "FUNCTIONS_EXTENSION_VERSION": "~0.3" 67 | }, 68 | "type": "config" 69 | }, 70 | { 71 | "apiVersion": "2016-03-01", 72 | "dependsOn": [ 73 | "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]", 74 | "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" 75 | ], 76 | "name": "[concat(variables('functionAppName'), '/', variables('functionName'))]", 77 | "type": "Microsoft.Web/sites/functions", 78 | "properties": { 79 | "files": { 80 | "index.js": "// function has low usage gets message, reads it count to 1000 and finishes\r\n\r\nmodule.exports = function (context, size) {\r\n context.log(\"Function started with input \" + size);\r\n\r\n for(var i = 0; i < 1000; i++){\r\n context.log(i);\r\n }\r\n \r\n context.done();\r\n}\r\n" 81 | }, 82 | "config": { 83 | "bindings": [ 84 | { 85 | "type": "queueTrigger", 86 | "name": "input", 87 | "direction": "in", 88 | "queueName": "samples-node-js-low-usage-test" 89 | } 90 | ] 91 | } 92 | } 93 | } 94 | ], 95 | "type": "Microsoft.Web/sites" 96 | } 97 | ], 98 | "variables": { 99 | "functionAppName": "[concat('queue-nodejs-low-usage', uniquestring(resourceGroup().id))]", 100 | "functionName": "function", 101 | "hostingPlanName": "[concat('queue-nodejs-low-usage', uniquestring(resourceGroup().id))]", 102 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azfunctions')]" 103 | } 104 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-LowUsage/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "type": "queueTrigger", 5 | "name": "input", 6 | "direction": "in", 7 | "queueName": "samples-node-js-low-usage-test", 8 | "connection": "" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/Queue-NodeJs-LowUsage/index.js: -------------------------------------------------------------------------------- 1 | // function has low usage gets message, reads it count to 1000 and finishes 2 | 3 | module.exports = function (context, size) { 4 | context.log("Function started with input " + size); 5 | 6 | for(var i = 0; i < 1000; i++){ 7 | context.log(i); 8 | } 9 | 10 | context.done(); 11 | } -------------------------------------------------------------------------------- /SampleUsages/TestSamples/README.html: -------------------------------------------------------------------------------- 1 | #Tests samples required to run the according tests. 2 | 3 | ## Queue-Node-Js-CPU-Intensive 4 | 5 |

6 | Function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size 7 | then in multiplies matrixes, prints "Finish." when calculation is done. 8 | This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower 9 |

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ## Queue-Node-Js-High-Memory 20 | 21 |

22 | Function is designed to allocate big array depending on input size. 23 |

24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ## Queue-Node-Js-Low-Usage 34 | 35 |

36 | Function has low usage gets message, reads it count to 1000 and finishes. 37 |

38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /SampleUsages/TestSamples/README.md: -------------------------------------------------------------------------------- 1 | #Tests samples required to run the according tests. 2 | 3 | ## Queue-Node-Js-CPU-Intensive 4 | 5 |

6 | Function is triggered by queue input. Input ia a number and function generates to random square matixes of input x input size 7 | then in multiplies matrixes, prints "Finish." when calculation is done. 8 | This operation is very heavily using CPU resources, concurrent executions on single container cause function to execute slower 9 |

10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ## Queue-Node-Js-High-Memory 20 | 21 |

22 | Function is designed to allocate big array depending on input size. 23 |

24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ## Queue-Node-Js-Low-Usage 34 | 35 |

36 | Function has low usage gets message, reads it count to 1000 and finishes. 37 |

38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /SampleUsages/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /ServerlessBenchmark.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerlessBenchmark", "ServerlessBenchmark\ServerlessBenchmark.csproj", "{582CC16B-6C75-494B-B27F-7A769DEC0C30}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniCommandLineHelper", "MiniCommandLineHelper\MiniCommandLineHelper.csproj", "{600BA962-07EA-46EC-B8F5-9BC5933C5533}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleUsages", "SampleUsages\SampleUsages.csproj", "{6B65B2D7-6344-4B15-A428-483E74E9AF51}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {582CC16B-6C75-494B-B27F-7A769DEC0C30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {582CC16B-6C75-494B-B27F-7A769DEC0C30}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {582CC16B-6C75-494B-B27F-7A769DEC0C30}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {582CC16B-6C75-494B-B27F-7A769DEC0C30}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {600BA962-07EA-46EC-B8F5-9BC5933C5533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {600BA962-07EA-46EC-B8F5-9BC5933C5533}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {600BA962-07EA-46EC-B8F5-9BC5933C5533}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {600BA962-07EA-46EC-B8F5-9BC5933C5533}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {6B65B2D7-6344-4B15-A428-483E74E9AF51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {6B65B2D7-6344-4B15-A428-483E74E9AF51}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {6B65B2D7-6344-4B15-A428-483E74E9AF51}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {6B65B2D7-6344-4B15-A428-483E74E9AF51}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /ServerlessBenchmark/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ServerlessBenchmark/Constants.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ServerlessBenchmark 4 | { 5 | public static class Constants 6 | { 7 | public const string InsertionTime = "InsertionTime"; 8 | public const string Topic = "Topic"; 9 | public const string Message = "Message"; 10 | public const string Queue = "QueueUrl"; 11 | public const int MaxDequeueAmount = 32; 12 | 13 | /// 14 | /// The name of the table where all of the azure function execution logs are stored. 15 | /// 16 | public const string AzureFunctionLogTableName = "AzureFunctionsLogTable"; 17 | 18 | /// 19 | /// Partition key of the execution logs that carries information such as container and etc. 20 | /// 21 | public const string AzureFunctionLogExecutionPartitionKey = "R"; 22 | 23 | /// 24 | /// Timeout in milliseconds for each http request 25 | /// 26 | public const int HttpTriggerTimeoutMilliseconds = 300 * 1000; 27 | 28 | public const int LoadCoolDownTimeout = 180 * 1000; 29 | } 30 | 31 | public enum TriggerTypes { Blob, Queue, Http} 32 | } 33 | -------------------------------------------------------------------------------- /ServerlessBenchmark/LoadProfiles/LinearLoad.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace ServerlessBenchmark.LoadProfiles 5 | { 6 | /// 7 | /// This load profile just follows the basic definition of linear. 8 | /// y = mx + b 9 | /// 10 | public class LinearLoad:TriggerTestLoadProfile 11 | { 12 | private int _totalNumberOfPostItems; 13 | private readonly int _targetEps; 14 | private int _isFinished; 15 | 16 | /// 17 | /// Given some duration, run linear pattern load against a function. 18 | /// 19 | /// 20 | /// This is target executions per second 21 | public LinearLoad(TimeSpan loadDuration, int eps) : base(loadDuration) 22 | { 23 | _targetEps = eps; 24 | } 25 | 26 | /// 27 | /// Run linear pattern load against a function. 28 | /// 29 | /// 30 | /// This is target executions per second 31 | public LinearLoad(int totalNumberOfPostItems, int eps) : base(TimeSpan.FromMilliseconds(Int32.MaxValue)) 32 | { 33 | _targetEps = eps; 34 | _totalNumberOfPostItems = totalNumberOfPostItems; 35 | } 36 | 37 | protected override int ExecuteRate(int t) 38 | { 39 | if (_totalNumberOfPostItems > 0 && _targetEps > 0) 40 | { 41 | _totalNumberOfPostItems = Math.Max(_targetEps, _totalNumberOfPostItems) - Math.Min(_targetEps, _totalNumberOfPostItems); 42 | if (_totalNumberOfPostItems <= 0) 43 | { 44 | Interlocked.Increment(ref _isFinished); 45 | } 46 | } 47 | const int slope = 0; 48 | return slope*t + _targetEps; 49 | } 50 | 51 | protected override bool IsFinished() 52 | { 53 | return _isFinished == 1; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ServerlessBenchmark/LoadProfiles/TriggerTestLoadProfile.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | //------------------------------------------------------------ 4 | using System; 5 | 6 | using System.Collections.Generic; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace ServerlessBenchmark.LoadProfiles 11 | { 12 | /// 13 | /// Base class for load profiles 14 | /// 15 | public abstract class TriggerTestLoadProfile:IDisposable 16 | { 17 | protected TimeSpan LoadDuration; 18 | private Timer _calculateRateTimer; 19 | private int _timeCounter = -1; 20 | private List _runningTasks; 21 | 22 | protected TriggerTestLoadProfile(TimeSpan loadDuration) 23 | { 24 | LoadDuration = loadDuration; 25 | _runningTasks = new List(); 26 | } 27 | 28 | /// 29 | /// Given a duration and action, calculate rate of publishing items and execute the given action. 30 | /// 31 | /// 32 | public async Task ExecuteRateAsync(Func action) 33 | { 34 | TimerCallback callback = async t => 35 | { 36 | Interlocked.Increment(ref _timeCounter); 37 | int rate = ExecuteRate(_timeCounter); 38 | var loadAction = action(rate); 39 | _runningTasks.Add(loadAction); 40 | await loadAction; 41 | }; 42 | _calculateRateTimer = new Timer(callback, null, 0, 1000 * 1); 43 | var isLoadFinishedTask = Task.Run(() => 44 | { 45 | while (!IsFinished()) 46 | { 47 | //keep cycling 48 | Task.Delay(TimeSpan.FromSeconds(1)); 49 | } 50 | }); 51 | 52 | var loadDurationTimerTask = Task.Delay(LoadDuration + TimeSpan.FromSeconds(1)); 53 | 54 | await Task.WhenAny(loadDurationTimerTask, isLoadFinishedTask); 55 | } 56 | 57 | protected abstract int ExecuteRate(int t); 58 | 59 | protected abstract bool IsFinished(); 60 | 61 | public void Dispose() 62 | { 63 | _calculateRateTimer.Dispose(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ServerlessBenchmark/MetricInfo/Metric.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ServerlessBenchmark.MetricInfo 4 | { 5 | public sealed class Metric:IEquatable 6 | { 7 | public string Name { get; private set; } 8 | public Metric(string metricName) 9 | { 10 | if (!string.IsNullOrEmpty(metricName)) 11 | { 12 | Name = metricName; 13 | } 14 | else 15 | { 16 | throw new ArgumentNullException("metricName"); 17 | } 18 | } 19 | 20 | public bool Equals(Metric other) 21 | { 22 | return Name.Equals(other.Name, StringComparison.CurrentCultureIgnoreCase); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ServerlessBenchmark/MetricInfo/PerfMetrics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServerlessBenchmark.MetricInfo 8 | { 9 | public enum PerfMetrics 10 | { 11 | ExecutionTimeStandardDeviation, 12 | ExecutionCount, 13 | FunctionClockTime, 14 | AverageExecutionTime, 15 | Throughput, 16 | HostConcurrency, 17 | ThroughputGraph 18 | } 19 | 20 | [AttributeUsage(AttributeTargets.Method)] 21 | public sealed class PerfMetric : Attribute 22 | { 23 | public string MetricName { get; private set; } 24 | public PerfMetric(PerfMetrics metric) 25 | { 26 | MetricName = Enum.GetName(typeof (PerfMetrics), metric); 27 | } 28 | 29 | public PerfMetric(string metricName) 30 | { 31 | MetricName = metricName; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ServerlessBenchmark/PerfResultProviders/AwsGenericPerformanceResultsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Amazon.CloudWatchLogs.Model; 4 | using ServerlessBenchmark.MetricInfo; 5 | 6 | namespace ServerlessBenchmark.PerfResultProviders 7 | { 8 | public sealed class AwsGenericPerformanceResultsProvider:AwsPerformanceResultProviderBase 9 | { 10 | protected override Dictionary ObtainAdditionalPerfMetrics(PerfTestResult genericPerfTestResult, 11 | string functionName, DateTime testStartTime, DateTime testEndTime, List lambdaExecutionLogs) 12 | { 13 | return null; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ServerlessBenchmark/PerfResultProviders/AzureGenericPerformanceResultsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServerlessBenchmark.PerfResultProviders 8 | { 9 | public class AzureGenericPerformanceResultsProvider : AzurePerformanceResultProviderBase 10 | { 11 | protected override Dictionary ObtainAdditionalPerfMetrics(PerfTestResult genericPerfTestResult, string functionName, DateTime testStartTime, 12 | DateTime testEndTime) 13 | { 14 | return null; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ServerlessBenchmark/PerfResultProviders/FunctionLogs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Amazon.CloudWatchLogs; 9 | using Amazon.CloudWatchLogs.Model; 10 | using Microsoft.WindowsAzure.Storage; 11 | using Microsoft.WindowsAzure.Storage.Table; 12 | 13 | namespace ServerlessBenchmark.PerfResultProviders 14 | { 15 | internal class FunctionLogs 16 | { 17 | private static List _azurefunctionLogs; 18 | public static List GetAzureFunctionLogs(string functionName, DateTime? startTime, DateTime? endTime, bool update = false, int expectedExecutionCount = 0) 19 | { 20 | return GetAzureFunctionLogsInternal(functionName, startTime, endTime, update, expectedExecutionCount); 21 | } 22 | 23 | public static List GetAzureFunctionLogs(DateTime? startTime, DateTime? endTime, bool update = false, int expectedExecutionCount = 0) 24 | { 25 | return GetAzureFunctionLogsInternal(string.Empty, startTime, endTime, update, expectedExecutionCount); 26 | } 27 | 28 | public static List GetAzureFunctionLogs(string functionName, bool allLogs = false) 29 | { 30 | return GetAzureFunctionLogsInternal(functionName, null, null); 31 | } 32 | 33 | public static bool RemoveAllCLoudWatchLogs(string functionName) 34 | { 35 | bool isEmpty; 36 | using (var cwClient = new AmazonCloudWatchLogsClient()) 37 | { 38 | var logStreams = GetAllLogStreams(functionName, cwClient); 39 | Console.WriteLine("Deleting Log Streams"); 40 | logStreams.ForEach(s => cwClient.DeleteLogStream(new DeleteLogStreamRequest("/aws/lambda/" + functionName, s.LogStreamName))); 41 | isEmpty = GetAllLogStreams(functionName, cwClient).Count == 0; 42 | } 43 | return isEmpty; 44 | } 45 | 46 | private static List GetAzureFunctionLogsInternal(string functionName, DateTime? startTime, DateTime? endTime, bool update = false, int expectedExecutionCount = 0, int waitForAllLogsTimeoutInMinutes = 5) 47 | { 48 | Console.WriteLine("Getting Azure Function logs from Azure Storage Tables.."); 49 | var connectionString = ConfigurationManager.AppSettings["AzureStorageConnectionString"]; 50 | 51 | if (!string.IsNullOrEmpty(connectionString)) 52 | { 53 | var storageAccount = CloudStorageAccount.Parse(connectionString); 54 | var tableClient = storageAccount.CreateCloudTableClient(); 55 | var table = tableClient.GetTableReference("AzureFunctionsLogTable"); 56 | var query = new TableQuery(); 57 | int size = 0; 58 | var latestNewLog = DateTime.UtcNow; 59 | var lastSize = 0; 60 | 61 | do 62 | { 63 | _azurefunctionLogs = table.ExecuteQuery(query).Where(log => string.IsNullOrEmpty(functionName) || (!string.IsNullOrEmpty(log.FunctionName) && 64 | log.FunctionName.Equals(functionName, StringComparison.CurrentCultureIgnoreCase) && !string.IsNullOrEmpty(log.ContainerName))).ToList(); 65 | size = _azurefunctionLogs.Count(); 66 | 67 | if (lastSize != size) 68 | { 69 | lastSize = size; 70 | latestNewLog = DateTime.UtcNow; 71 | } 72 | else 73 | { 74 | var secondsSinceLastNewLog = (DateTime.UtcNow - latestNewLog).TotalSeconds; 75 | var secondsStillToWait = 60*waitForAllLogsTimeoutInMinutes - secondsSinceLastNewLog; 76 | Console.WriteLine( 77 | "No new log for {0} seconds. Waiting another {1}s to finish.", 78 | secondsSinceLastNewLog, 79 | secondsStillToWait 80 | ); 81 | } 82 | 83 | if (expectedExecutionCount == 0) 84 | { 85 | break; 86 | } 87 | 88 | Console.WriteLine("Log count {0} expected {1}", size, expectedExecutionCount); 89 | 90 | if ((DateTime.UtcNow - latestNewLog).TotalMinutes >= waitForAllLogsTimeoutInMinutes) 91 | { 92 | Console.WriteLine("Not all result logs have been found! No new logs appeared in last {0} minutes. Finishing wait to present results.", waitForAllLogsTimeoutInMinutes); 93 | break; 94 | } 95 | 96 | Thread.Sleep(1000); 97 | } while (size < expectedExecutionCount); 98 | } 99 | 100 | return _azurefunctionLogs; 101 | } 102 | 103 | private static List GetAllLogStreams(string functionName, AmazonCloudWatchLogsClient cwClient) 104 | { 105 | var logStreams = new List(); 106 | DescribeLogStreamsResponse lResponse; 107 | string nextToken = null; 108 | do 109 | { 110 | lResponse = 111 | cwClient.DescribeLogStreams(new DescribeLogStreamsRequest("/aws/lambda/" + functionName) 112 | { 113 | NextToken = nextToken 114 | }); 115 | logStreams.AddRange(lResponse.LogStreams); 116 | } while (!string.IsNullOrEmpty(nextToken = lResponse.NextToken)); 117 | return logStreams; 118 | } 119 | 120 | public class AzureFunctionLogs : TableEntity 121 | { 122 | public string FunctionName { get; set; } 123 | public DateTime StartTime { get; set; } 124 | public DateTime EndTime { get; set; } 125 | public string ContainerName { get; set; } 126 | public Int32 TotalFail { get; set; } 127 | public Int32 TotalPass { get; set; } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /ServerlessBenchmark/PerfResultProviders/PerfResultProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using OxyPlot; 8 | using OxyPlot.Axes; 9 | using OxyPlot.Series; 10 | using ServerlessBenchmark.MetricInfo; 11 | 12 | namespace ServerlessBenchmark.PerfResultProviders 13 | { 14 | public abstract class PerfResultProvider 15 | { 16 | protected void PrintThrouputGraph(Dictionary data, string fileName, int timeResolutionInSeconds) 17 | { 18 | var stringBuffer = new StringBuilder(); 19 | 20 | var model = new PlotModel { Title = "AWS throuput in time (items finished/second)" }; 21 | var timeAxis = new DateTimeAxis 22 | { 23 | StringFormat = "hh:mm:ss" 24 | }; 25 | 26 | model.Axes.Add(timeAxis); 27 | var series = new LineSeries(); 28 | 29 | foreach (var log in data.OrderBy(l => l.Key)) 30 | { 31 | stringBuffer.AppendFormat("{0},{1}{2}", log.Value / timeResolutionInSeconds, log.Key, Environment.NewLine); 32 | series.Points.Add(new DataPoint(DateTimeAxis.ToDouble(log.Key), log.Value / timeResolutionInSeconds)); 33 | } 34 | 35 | model.Series.Add(series); 36 | 37 | using (var stream = File.Create(fileName)) 38 | { 39 | var pdfExporter = new PdfExporter { Width = 600, Height = 400 }; 40 | pdfExporter.Export(model, stream); 41 | } 42 | } 43 | 44 | protected abstract Dictionary ObtainAdditionalPerfMetrics(PerfTestResult genericPerfTestResult, string functionName, DateTime testStartTime, DateTime testEndTime); 45 | 46 | public virtual PerfTestResult GetPerfMetrics(string functionName, DateTime testStartTime, DateTime testEndTime,string inputTriggerName = null, string outputTriggerName = null, int expectedExecutionCount = 0) 47 | { 48 | var perfResults = new PerfTestResult(); 49 | var perfCalculatingMethods = GetType().GetRuntimeMethods().Where(m => m.IsDefined(typeof (PerfMetric))); 50 | foreach (var method in perfCalculatingMethods) 51 | { 52 | var result = method.Invoke(this, new object[]{functionName, testStartTime, testEndTime}).ToString(); 53 | var perfMetricAttribute = method.GetCustomAttribute(typeof (PerfMetric)) as PerfMetric; 54 | var metricName = perfMetricAttribute.MetricName; 55 | perfResults.AddMetric(metricName, result); 56 | } 57 | 58 | var additionalPerfResults = ObtainAdditionalPerfMetrics(perfResults, functionName, testStartTime, testEndTime) ?? new Dictionary(); 59 | var additionalPerfResultsList = additionalPerfResults.ToList(); 60 | foreach (var additionalPerfResult in additionalPerfResultsList) 61 | { 62 | perfResults.AddMetric(additionalPerfResult.Key, additionalPerfResult.Value); 63 | } 64 | return perfResults; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ServerlessBenchmark/PerfTestResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using ServerlessBenchmark.MetricInfo; 6 | 7 | namespace ServerlessBenchmark 8 | { 9 | public class PerfTestResult : SortedList 10 | { 11 | public void AddMetric(string metricName, string val) 12 | { 13 | Add(metricName, val); 14 | } 15 | 16 | public override string ToString() 17 | { 18 | var sb = new StringBuilder(); 19 | var list = this.ToList(); 20 | foreach (var metric in list) 21 | { 22 | sb.AppendFormat("{0} {1}\n", metric.Key, metric.Value); 23 | } 24 | return sb.ToString(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ServerlessBenchmark/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServerlessBenchmark")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServerlessBenchmark")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("e232a8ea-2118-46bd-9264-0b5d32348387")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ServerlessBenchmark/ServerlessBenchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {582CC16B-6C75-494B-B27F-7A769DEC0C30} 8 | Library 9 | Properties 10 | ServerlessBenchmark 11 | ServerlessBenchmark 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\AWSSDK.CloudWatch.3.1.0.7\lib\net45\AWSSDK.CloudWatch.dll 35 | 36 | 37 | ..\packages\AWSSDK.CloudWatchLogs.3.1.2.6\lib\net45\AWSSDK.CloudWatchLogs.dll 38 | 39 | 40 | ..\packages\AWSSDK.Core.3.1.7.0\lib\net45\AWSSDK.Core.dll 41 | 42 | 43 | ..\packages\AWSSDK.Lambda.3.1.4.2\lib\net45\AWSSDK.Lambda.dll 44 | 45 | 46 | ..\packages\AWSSDK.S3.3.1.7.2\lib\net45\AWSSDK.S3.dll 47 | 48 | 49 | ..\packages\AWSSDK.SimpleNotificationService.3.1.0.7\lib\net45\AWSSDK.SimpleNotificationService.dll 50 | 51 | 52 | ..\packages\AWSSDK.SQS.3.1.0.10\lib\net45\AWSSDK.SQS.dll 53 | 54 | 55 | ..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll 56 | 57 | 58 | False 59 | ..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll 60 | 61 | 62 | False 63 | ..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll 64 | 65 | 66 | False 67 | ..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll 68 | 69 | 70 | False 71 | ..\packages\WindowsAzure.Storage.7.0.0\lib\net40\Microsoft.WindowsAzure.Storage.dll 72 | 73 | 74 | ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll 75 | 76 | 77 | ..\packages\OxyPlot.Core.1.0.0-unstable2100\lib\net45\OxyPlot.dll 78 | True 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | False 87 | ..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 144 | -------------------------------------------------------------------------------- /ServerlessBenchmark/ServerlessPlatformControllers/AWS/AWS_CloudPlatformResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amazon.Runtime; 3 | 4 | namespace ServerlessBenchmark.ServerlessPlatformControllers.AWS 5 | { 6 | public class AwsCloudPlatformResponse:CloudPlatformResponse 7 | { 8 | public static AwsCloudPlatformResponse PopulateFrom(AmazonWebServiceResponse response) 9 | { 10 | if (response == null) 11 | { 12 | return null; 13 | } 14 | string insertionTime; 15 | DateTime insertionDateTime; 16 | response.ResponseMetadata.Metadata.TryGetValue(Constants.InsertionTime, out insertionTime); 17 | DateTime.TryParse(insertionTime, out insertionDateTime); 18 | var genericPlatformReponse = new AwsCloudPlatformResponse() 19 | { 20 | HttpStatusCode = response.HttpStatusCode, 21 | TimeStamp = insertionDateTime 22 | }; 23 | return genericPlatformReponse; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ServerlessBenchmark/ServerlessPlatformControllers/CloudPlatformController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace ServerlessBenchmark.ServerlessPlatformControllers 4 | { 5 | /// 6 | /// Interface that serverless benchmark uses to communicate with the serverless platform. 7 | /// 8 | public interface ICloudPlatformController 9 | { 10 | CloudPlatformResponse PostMessage(CloudPlatformRequest request); 11 | CloudPlatformResponse PostMessages(CloudPlatformRequest request); 12 | Task PostMessagesAsync(CloudPlatformRequest request); 13 | CloudPlatformResponse GetMessage(CloudPlatformRequest request); 14 | CloudPlatformResponse GetMessages(CloudPlatformRequest request); 15 | CloudPlatformResponse DeleteMessages(CloudPlatformRequest request); 16 | Task EnqueueMessagesAsync(CloudPlatformRequest request); 17 | Task DequeueMessagesAsync(CloudPlatformRequest request); 18 | CloudPlatformResponse PostBlob(CloudPlatformRequest request); 19 | Task PostBlobAsync(CloudPlatformRequest request); 20 | Task PostBlobsAsync(CloudPlatformRequest request); 21 | CloudPlatformResponse ListBlobs(CloudPlatformRequest request); 22 | CloudPlatformResponse DeleteBlobs(CloudPlatformRequest request); 23 | CloudPlatformResponse GetFunctionName(string inputContainerName); 24 | CloudPlatformResponse GetInputOutputTriggers(string functionName); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ServerlessBenchmark/ServerlessPlatformControllers/CloudPlatformRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace ServerlessBenchmark.ServerlessPlatformControllers 6 | { 7 | public class CloudPlatformRequest 8 | { 9 | public DateTime TimeStamp { get; set; } 10 | public int RequestId { get; set; } 11 | public Dictionary Data { get; set; } 12 | public string Source { get; set; } 13 | public Stream DataStream { get; set; } 14 | public string Key { get; set; } 15 | public int MessageCount { get; set; } 16 | public bool Retry { get; set; } 17 | public int RetryAttempts { get; set; } 18 | public int? TimeoutMilliseconds { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ServerlessBenchmark/ServerlessPlatformControllers/CloudPlatformResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ServerlessBenchmark.ServerlessPlatformControllers 5 | { 6 | public class CloudPlatformResponse 7 | { 8 | public int ResponseId { get; set; } 9 | public System.Net.HttpStatusCode HttpStatusCode { get; set; } 10 | public DateTime TimeStamp { get; set; } 11 | public Dictionary TimeStamps { get; set; } 12 | public object Data { get; set; } 13 | 14 | public Dictionary ErrorDetails { get; private set; } 15 | 16 | public CloudPlatformResponse() 17 | { 18 | ErrorDetails = new Dictionary(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ServerlessBenchmark/SupplementalPerfTestResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ServerlessBenchmark 5 | { 6 | sealed internal class SupplementalPerfTestResult:PerfTestResult 7 | { 8 | private Dictionary _supplementalPerformanceTestResults; 9 | internal Dictionary SupplementalPerformanceTestResults { 10 | get 11 | { 12 | if (_supplementalPerformanceTestResults == null) 13 | { 14 | _supplementalPerformanceTestResults = new Dictionary(); 15 | } 16 | return _supplementalPerformanceTestResults; 17 | } 18 | } 19 | 20 | public override string ToString() 21 | { 22 | var perfResults = base.ToString(); 23 | foreach (var metric in SupplementalPerformanceTestResults) 24 | { 25 | perfResults += String.Format("{0} {1}\n", metric.Key, metric.Value); 26 | } 27 | return perfResults; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TestRequest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ServerlessBenchmark 4 | { 5 | public class TestRequest 6 | { 7 | private const int DefaultRetries = 5; 8 | private int _retries = 0; 9 | public IEnumerable Messages { get; set; } 10 | public string SrcQueue { get; set; } 11 | public string DstQueue { get; set; } 12 | public int[] DistributedBatchMessageSizes { get; set; } 13 | public string CloudPlatform { get; set; } 14 | 15 | public int Retries 16 | { 17 | get 18 | { 19 | if (_retries == 0) 20 | { 21 | return DefaultRetries; 22 | } 23 | return _retries; 24 | } 25 | set { _retries = value; } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/AWS/AmazonApiGatewayTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using ServerlessBenchmark.PerfResultProviders; 2 | using ServerlessBenchmark.ServerlessPlatformControllers; 3 | using ServerlessBenchmark.ServerlessPlatformControllers.AWS; 4 | using ServerlessBenchmark.TriggerTests.BaseTriggers; 5 | 6 | namespace ServerlessBenchmark.TriggerTests.AWS 7 | { 8 | public class AmazonApiGatewayTriggerTest:HttpTriggerTest 9 | { 10 | public AmazonApiGatewayTriggerTest(string functionName, string[] urls) : base(functionName, urls) 11 | { 12 | } 13 | 14 | protected override bool Setup() 15 | { 16 | return FunctionLogs.RemoveAllCLoudWatchLogs(FunctionName); 17 | } 18 | 19 | protected override ICloudPlatformController CloudPlatformController 20 | { 21 | get { return new AwsController(); } 22 | } 23 | 24 | protected override PerfResultProvider PerfmormanceResultProvider 25 | { 26 | get { return new AwsGenericPerformanceResultsProvider(); } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/AWS/AmazonS3TriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using ServerlessBenchmark.PerfResultProviders; 4 | using ServerlessBenchmark.ServerlessPlatformControllers; 5 | using ServerlessBenchmark.ServerlessPlatformControllers.AWS; 6 | using ServerlessBenchmark.TriggerTests.BaseTriggers; 7 | 8 | namespace ServerlessBenchmark.TriggerTests.AWS 9 | { 10 | public class AmazonS3TriggerTest:BlobTriggerTest 11 | { 12 | 13 | public AmazonS3TriggerTest(string functionName, IEnumerable blobs, string sourceBlobContainer, 14 | string destinationBlobContainer) 15 | : base(functionName, blobs.ToArray(), sourceBlobContainer, destinationBlobContainer) 16 | { 17 | 18 | } 19 | 20 | protected override bool Setup() 21 | { 22 | return FunctionLogs.RemoveAllCLoudWatchLogs(FunctionName); 23 | } 24 | 25 | protected override ICloudPlatformController CloudPlatformController 26 | { 27 | get { return new AwsController(); } 28 | } 29 | 30 | protected override PerfResultProvider PerfmormanceResultProvider 31 | { 32 | get { return new AwsGenericPerformanceResultsProvider(); } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/AWS/AmazonSnsToSqs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using ServerlessBenchmark.ServerlessPlatformControllers; 8 | 9 | namespace ServerlessBenchmark.TriggerTests.AWS 10 | { 11 | public class AmazonSnsToSqs : AmazonSqsTriggerTest 12 | { 13 | private string _sourceTopic; 14 | public AmazonSnsToSqs(string functionName, IEnumerable messages, string sourceTopic, string destinationQueue) : base(functionName, messages, sourceTopic, destinationQueue) 15 | { 16 | _sourceTopic = sourceTopic; 17 | } 18 | 19 | protected override string StorageType 20 | { 21 | get { return "SnsToQueue"; } 22 | } 23 | 24 | protected override List CleanUpStorageResources() 25 | { 26 | var responses = new List(); 27 | List cloudPlatformResponses = null; 28 | try 29 | { 30 | cloudPlatformResponses = new List 31 | { 32 | {CloudPlatformController.DeleteMessages(new CloudPlatformRequest() {Source = TargetQueue})} 33 | }; 34 | responses.AddRange(cloudPlatformResponses); 35 | } 36 | catch (Exception e) 37 | { 38 | Console.WriteLine(e); 39 | throw; 40 | } 41 | return responses; 42 | } 43 | 44 | protected async override Task UploadItems(IEnumerable items) 45 | { 46 | //instead of sending messages to queue send to SNS topic 47 | await CloudPlatformController.PostMessagesAsync(new CloudPlatformRequest() 48 | { 49 | Data = new Dictionary() 50 | { 51 | {Constants.Message, items}, 52 | {Constants.Topic, _sourceTopic} 53 | }, 54 | Retry = true, 55 | RetryAttempts = 3, 56 | TimeoutMilliseconds = (int?) TimeSpan.FromSeconds(45).TotalMilliseconds 57 | }); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/AWS/AmazonSqsTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using ServerlessBenchmark.PerfResultProviders; 4 | using ServerlessBenchmark.ServerlessPlatformControllers; 5 | using ServerlessBenchmark.ServerlessPlatformControllers.AWS; 6 | using ServerlessBenchmark.TriggerTests.BaseTriggers; 7 | 8 | namespace ServerlessBenchmark.TriggerTests.AWS 9 | { 10 | public class AmazonSqsTriggerTest:QueueTriggerTest 11 | { 12 | public AmazonSqsTriggerTest(string functionName, IEnumerable queueMessages, string sourceBlobContainer, 13 | string destinationBlobContainer) 14 | : base(functionName, queueMessages.ToArray(), sourceBlobContainer, destinationBlobContainer) 15 | { 16 | 17 | } 18 | 19 | protected override bool Setup() 20 | { 21 | return FunctionLogs.RemoveAllCLoudWatchLogs(FunctionName); 22 | } 23 | 24 | protected override ICloudPlatformController CloudPlatformController 25 | { 26 | get { return new AwsController(); } 27 | } 28 | 29 | protected override PerfResultProvider PerfmormanceResultProvider 30 | { 31 | get { return new AwsGenericPerformanceResultsProvider(); } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/Azure/AzureBlobTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Configuration; 3 | using System.Linq; 4 | using Microsoft.WindowsAzure.Storage; 5 | using Microsoft.WindowsAzure.Storage.Table; 6 | using ServerlessBenchmark.PerfResultProviders; 7 | using ServerlessBenchmark.ServerlessPlatformControllers; 8 | using ServerlessBenchmark.ServerlessPlatformControllers.Azure; 9 | using ServerlessBenchmark.TriggerTests.BaseTriggers; 10 | 11 | namespace ServerlessBenchmark.TriggerTests.Azure 12 | { 13 | public class AzureBlobTriggerTest:BlobTriggerTest 14 | { 15 | public AzureBlobTriggerTest(string functionName, IEnumerable blobs, string inputContainer, 16 | string outputContainer) : base(functionName, blobs.ToArray(), inputContainer, outputContainer) 17 | { 18 | 19 | } 20 | 21 | public AzureBlobTriggerTest(string functionName, IEnumerable blobs) 22 | { 23 | //todo find the input and output container given the container name 24 | } 25 | 26 | protected override bool Setup() 27 | { 28 | return RemoveAzureFunctionLogs() && EnableLoggingIfDisabled(); 29 | } 30 | 31 | protected override ICloudPlatformController CloudPlatformController 32 | { 33 | get { return new AzureController(); } 34 | } 35 | 36 | protected override PerfResultProvider PerfmormanceResultProvider 37 | { 38 | get { return new AzureGenericPerformanceResultsProvider(); } 39 | } 40 | 41 | private bool RemoveAzureFunctionLogs() 42 | { 43 | var connectionString = ConfigurationManager.AppSettings["AzureStorageConnectionString"]; 44 | if (!string.IsNullOrEmpty(connectionString)) 45 | { 46 | var operationContext = new OperationContext(); 47 | var storageAccount = CloudStorageAccount.Parse(connectionString); 48 | var tableClient = storageAccount.CreateCloudTableClient(); 49 | var logs = FunctionLogs.GetAzureFunctionLogs(FunctionName); 50 | var table = tableClient.GetTableReference("AzureFunctionsLogTable"); 51 | logs.ForEach(entity => table.Execute(TableOperation.Delete(entity))); 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | private bool EnableLoggingIfDisabled() 58 | { 59 | var connectionString = ConfigurationManager.AppSettings["AzureStorageConnectionString"]; 60 | var operationContext = new OperationContext(); 61 | var storageAccount = CloudStorageAccount.Parse(connectionString); 62 | var blobClient = storageAccount.CreateCloudBlobClient(); 63 | var currentServiceProperties = blobClient.GetServiceProperties(); 64 | return true; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/Azure/AzureHttpTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Configuration; 3 | using System.Linq; 4 | using ServerlessBenchmark.PerfResultProviders; 5 | using ServerlessBenchmark.ServerlessPlatformControllers; 6 | using ServerlessBenchmark.ServerlessPlatformControllers.Azure; 7 | using ServerlessBenchmark.TriggerTests.BaseTriggers; 8 | 9 | namespace ServerlessBenchmark.TriggerTests.Azure 10 | { 11 | public class AzureHttpTriggerTest:HttpTriggerTest 12 | { 13 | public AzureHttpTriggerTest(string functionName, IEnumerable urls) : base(functionName, urls.ToArray()) 14 | { 15 | 16 | } 17 | 18 | protected override bool Setup() 19 | { 20 | return Utility.RemoveAzureFunctionLogs(FunctionName, 21 | ConfigurationManager.AppSettings["AzureStorageConnectionString"]); 22 | } 23 | 24 | protected override ICloudPlatformController CloudPlatformController 25 | { 26 | get { return new AzureController(); } 27 | } 28 | 29 | protected override PerfResultProvider PerfmormanceResultProvider 30 | { 31 | get { return new AzureGenericPerformanceResultsProvider(); } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/Azure/AzureQueueTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | using ServerlessBenchmark.PerfResultProviders; 3 | using ServerlessBenchmark.ServerlessPlatformControllers; 4 | using ServerlessBenchmark.ServerlessPlatformControllers.Azure; 5 | using ServerlessBenchmark.TriggerTests.BaseTriggers; 6 | 7 | namespace ServerlessBenchmark.TriggerTests.Azure 8 | { 9 | public class AzureQueueTriggerTest:QueueTriggerTest 10 | { 11 | public AzureQueueTriggerTest(string functionName, string[] messages, string sourceQueue, string targetQueue) : base(functionName, messages, sourceQueue, targetQueue) 12 | { 13 | } 14 | 15 | protected override ICloudPlatformController CloudPlatformController 16 | { 17 | get { return new AzureController(); } 18 | } 19 | 20 | protected override PerfResultProvider PerfmormanceResultProvider 21 | { 22 | get { return new AzureGenericPerformanceResultsProvider(); } 23 | } 24 | 25 | protected override bool Setup() 26 | { 27 | return Utility.RemoveAzureFunctionLogs(FunctionName, 28 | ConfigurationManager.AppSettings["AzureStorageConnectionString"]); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/BaseTriggers/BlobTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using ServerlessBenchmark.ServerlessPlatformControllers; 8 | 9 | namespace ServerlessBenchmark.TriggerTests.BaseTriggers 10 | { 11 | public abstract class BlobTriggerTest:StorageTriggerTest 12 | { 13 | protected readonly string SrcBlobContainer; 14 | protected readonly string DstBlobContainer; 15 | protected readonly string _functionName; 16 | 17 | protected BlobTriggerTest(string functionName, string[] blobs, string sourceBlobContainer, string destinationBlobContainer):base(functionName, blobs) 18 | { 19 | if (string.IsNullOrEmpty(functionName) || string.IsNullOrEmpty(sourceBlobContainer) || string.IsNullOrEmpty(destinationBlobContainer) 20 | || blobs == null) 21 | { 22 | throw new ArgumentException("Not all of the arguments are met"); 23 | } 24 | 25 | DstBlobContainer = destinationBlobContainer; 26 | SrcBlobContainer = sourceBlobContainer; 27 | _functionName = functionName; 28 | } 29 | 30 | public BlobTriggerTest():base(null, null) { } 31 | 32 | protected virtual string WarmUpBlob 33 | { 34 | get 35 | { 36 | return SourceItems.First(); 37 | } 38 | } 39 | 40 | protected override string StorageType 41 | { 42 | get { return "Blob"; } 43 | } 44 | 45 | protected override List CleanUpStorageResources() 46 | { 47 | var cloudPlatformResponses = new List 48 | { 49 | {CloudPlatformController.DeleteBlobs(new CloudPlatformRequest() {Source = SrcBlobContainer})}, 50 | {CloudPlatformController.DeleteBlobs(new CloudPlatformRequest() {Source = DstBlobContainer})} 51 | }; 52 | return cloudPlatformResponses; 53 | } 54 | 55 | protected override async Task UploadItems(IEnumerable items) 56 | { 57 | await UploadBlobs(items); 58 | } 59 | 60 | protected override Task VerifyTargetDestinationStorageCount(int expectedCount) 61 | { 62 | return Task.FromResult(VerifyBlobItemsExistInTargetDestination(expectedCount)); 63 | } 64 | 65 | private async Task UploadBlobs(IEnumerable blobs) 66 | { 67 | Parallel.ForEach(blobs, async blobPath => 68 | { 69 | using (FileStream stream = new FileStream(blobPath, FileMode.Open, FileAccess.Read, FileShare.Read)) 70 | { 71 | await CloudPlatformController.PostBlobAsync(new CloudPlatformRequest() 72 | { 73 | Key = Guid.NewGuid().ToString(), 74 | Source = SrcBlobContainer, 75 | DataStream = stream 76 | }); 77 | } 78 | }); 79 | } 80 | 81 | protected override Task TestCoolDown() 82 | { 83 | return Task.FromResult(true); 84 | } 85 | 86 | private bool VerifyBlobItemsExistInTargetDestination(int expected) 87 | { 88 | IEnumerable blobs; 89 | do 90 | { 91 | blobs = (IEnumerable)CloudPlatformController.ListBlobs(new CloudPlatformRequest() 92 | { 93 | Source = DstBlobContainer 94 | }).Data; 95 | Console.WriteLine("Destination Blobs - Number Of Blobs: {0}", blobs.Count()); 96 | Thread.Sleep(1 * 1000); 97 | } while (blobs.Count() < expected); 98 | return true; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/BaseTriggers/FunctionTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using ServerlessBenchmark.LoadProfiles; 9 | using ServerlessBenchmark.PerfResultProviders; 10 | using ServerlessBenchmark.ServerlessPlatformControllers; 11 | 12 | namespace ServerlessBenchmark.TriggerTests.BaseTriggers 13 | { 14 | public abstract class FunctionTest 15 | { 16 | protected string FunctionName { get; set; } 17 | protected abstract IEnumerable SourceItems { get; set; } 18 | protected int ExpectedExecutionCount; 19 | private int _executionsPerSecond; 20 | protected abstract bool TestSetupWithRetry(); 21 | protected abstract Task TestWarmup(); 22 | protected abstract Task TestCoolDown(); 23 | protected abstract Task PreReportGeneration(DateTime testStartTime, DateTime testEndTime); 24 | protected abstract ICloudPlatformController CloudPlatformController { get; } 25 | protected abstract PerfResultProvider PerfmormanceResultProvider { get; } 26 | private bool onTestCoolDown = false; 27 | 28 | protected FunctionTest(string functionName) 29 | { 30 | FunctionName = functionName; 31 | } 32 | 33 | public async Task RunAsync(TriggerTestLoadProfile loadProfile, bool warmup = true) 34 | { 35 | var retries = 3; 36 | bool isSuccessSetup; 37 | do 38 | { 39 | isSuccessSetup = TestSetupWithRetry(); 40 | retries = retries - 1; 41 | } while (retries > 0 && !isSuccessSetup); 42 | 43 | if (warmup) 44 | { 45 | await TestWarmup(); 46 | } 47 | 48 | Console.WriteLine("--START-- Running load"); 49 | var startTime = DateTime.Now; 50 | var sw = Stopwatch.StartNew(); 51 | await loadProfile.ExecuteRateAsync(GenerateLoad); 52 | loadProfile.Dispose(); 53 | onTestCoolDown = true; 54 | await TestCoolDown(); 55 | sw.Stop(); 56 | var clientEndTime = DateTime.Now; 57 | Console.WriteLine("--END-- Elapsed time: {0}", sw.Elapsed); 58 | await PreReportGeneration(startTime, clientEndTime); 59 | var perfResult = PerfmormanceResultProvider.GetPerfMetrics(FunctionName, startTime, clientEndTime, expectedExecutionCount: ExpectedExecutionCount); 60 | return perfResult; 61 | } 62 | 63 | protected abstract Task Load(IEnumerable requestItems); 64 | 65 | protected async Task GenerateLoad(int requests) 66 | { 67 | var srcNumberOfItems = SourceItems.Count(); 68 | List selectedItems; 69 | var randomResources = SourceItems.OrderBy(i => Guid.NewGuid()); 70 | if (requests <= srcNumberOfItems) 71 | { 72 | selectedItems = randomResources.Take(requests).ToList(); 73 | } 74 | else 75 | { 76 | var tmpList = new List(); 77 | do 78 | { 79 | tmpList.AddRange(randomResources.Take(requests)); 80 | requests -= srcNumberOfItems; 81 | } while (requests >= 0); 82 | selectedItems = tmpList; 83 | } 84 | _executionsPerSecond = selectedItems.Count; 85 | Console.WriteLine(PrintTestProgress()); 86 | Interlocked.Add(ref ExpectedExecutionCount, selectedItems.Count()); 87 | await Load(selectedItems); 88 | } 89 | 90 | protected virtual string PrintTestProgress(Dictionary testProgress = null) 91 | { 92 | var sb = new StringBuilder(); 93 | var progressData = testProgress ?? CurrentTestProgress(); 94 | sb.Append(DateTime.Now); 95 | foreach (var data in progressData) 96 | { 97 | sb.AppendFormat(" {0}: {1}", data.Key, data.Value); 98 | } 99 | sb.AppendLine(); 100 | return sb.ToString(); 101 | } 102 | 103 | protected virtual IDictionary CurrentTestProgress() 104 | { 105 | Dictionary progressData = null; 106 | if (!onTestCoolDown) 107 | { 108 | progressData = new Dictionary 109 | { 110 | {"EPS", _executionsPerSecond.ToString()} 111 | }; 112 | } 113 | return progressData; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/BaseTriggers/HttpTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Net.Security; 8 | using System.Security.Cryptography.X509Certificates; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using ServerlessBenchmark.PerfResultProviders; 12 | 13 | namespace ServerlessBenchmark.TriggerTests.BaseTriggers 14 | { 15 | /// 16 | /// Base HTTP function that all platform HTTP type functions can inherit from 17 | /// 18 | public abstract class HttpTriggerTest : FunctionTest 19 | { 20 | protected override sealed IEnumerable SourceItems { get; set; } 21 | private int _totalSuccessRequestsPerSecond; 22 | private int _totalFailedRequestsPerSecond; 23 | private int _totalTimedOutRequestsPerSecond; 24 | private int _totalActiveRequests; 25 | private readonly ConcurrentBag _responseTimes; 26 | private readonly ConcurrentDictionary> _runningTasks; 27 | private readonly List _loadRequests; 28 | 29 | protected abstract bool Setup(); 30 | 31 | protected HttpTriggerTest(string functionName, string[] urls):base(functionName) 32 | { 33 | if (!urls.Any()) 34 | { 35 | throw new ArgumentException("Urls is empty", "urls"); 36 | } 37 | if (String.IsNullOrEmpty(functionName)) 38 | { 39 | throw new ArgumentException("Function name cannot be empty", "functionName"); 40 | } 41 | 42 | SourceItems = urls.ToList(); 43 | _runningTasks = new ConcurrentDictionary>(); 44 | _loadRequests = new List(); 45 | _responseTimes = new ConcurrentBag(); 46 | 47 | ServicePointManager.ServerCertificateValidationCallback = 48 | delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 49 | { 50 | return true; 51 | }; 52 | } 53 | 54 | protected override Task TestWarmup() 55 | { 56 | var warmSite = SourceItems.First(); 57 | var client = new HttpClient(); 58 | var cs = new CancellationTokenSource(Constants.HttpTriggerTimeoutMilliseconds); 59 | HttpResponseMessage response; 60 | try 61 | { 62 | response = client.GetAsync(warmSite, cs.Token).Result; 63 | } 64 | catch (TaskCanceledException) 65 | { 66 | throw new Exception(String.Format("Warm up passed timeout of {0}ms", Constants.HttpTriggerTimeoutMilliseconds)); 67 | } 68 | 69 | var isSuccessfulSetup = response.IsSuccessStatusCode; 70 | return Task.FromResult(isSuccessfulSetup); 71 | } 72 | 73 | protected override bool TestSetupWithRetry() 74 | { 75 | return Setup(); 76 | } 77 | 78 | protected abstract override PerfResultProvider PerfmormanceResultProvider { get; } 79 | 80 | protected override Task PreReportGeneration(DateTime testStartTime, DateTime testEndTime) 81 | { 82 | return Task.FromResult(0); 83 | } 84 | 85 | protected async override Task Load(IEnumerable requestItems) 86 | { 87 | await LoadSites(requestItems); 88 | } 89 | 90 | private async Task LoadSites(IEnumerable sites) 91 | { 92 | var client = new HttpClient(); 93 | var loadRequests = new List(); 94 | foreach (var site in sites) 95 | { 96 | var t = Task.Run(async () => 97 | { 98 | DateTime requestSent = new DateTime(); 99 | try 100 | { 101 | var cs = new CancellationTokenSource(Constants.HttpTriggerTimeoutMilliseconds); 102 | var request = client.GetAsync(site, cs.Token); 103 | requestSent = DateTime.Now; 104 | Interlocked.Increment(ref _totalActiveRequests); 105 | if (!_runningTasks.TryAdd(request.Id, request)) 106 | { 107 | Console.WriteLine("Error on tracking this task"); 108 | } 109 | var response = await request; 110 | var responseReceived = DateTime.Now; 111 | Interlocked.Decrement(ref _totalActiveRequests); 112 | _responseTimes.Add((int)(responseReceived - requestSent).TotalMilliseconds); 113 | if (response.IsSuccessStatusCode) 114 | { 115 | Interlocked.Increment(ref _totalSuccessRequestsPerSecond); 116 | } 117 | else 118 | { 119 | Interlocked.Increment(ref _totalFailedRequestsPerSecond); 120 | } 121 | } 122 | catch (TaskCanceledException) 123 | { 124 | _responseTimes.Add((int)(DateTime.Now - requestSent).TotalMilliseconds); 125 | Interlocked.Increment(ref _totalTimedOutRequestsPerSecond); 126 | Interlocked.Decrement(ref _totalActiveRequests); 127 | } 128 | }); 129 | _loadRequests.Add(t); 130 | } 131 | await Task.WhenAll(loadRequests); 132 | } 133 | 134 | protected override async Task TestCoolDown() 135 | { 136 | if (_runningTasks.Any()) 137 | { 138 | var lastSize = 0; 139 | DateTime lastNewSize = new DateTime(); 140 | string testProgressString; 141 | while (true) 142 | { 143 | try 144 | { 145 | testProgressString = PrintTestProgress(); 146 | testProgressString = $"OutStanding: {_totalActiveRequests} {testProgressString}"; 147 | 148 | if (_totalActiveRequests == 0) 149 | { 150 | Console.WriteLine(testProgressString); 151 | Console.WriteLine("Finished Outstanding Requests"); 152 | break; 153 | } 154 | 155 | if (_totalActiveRequests != lastSize) 156 | { 157 | lastSize = _totalActiveRequests; 158 | lastNewSize = DateTime.Now; 159 | } 160 | else 161 | { 162 | var secondsSinceLastNewSize = (DateTime.Now - lastNewSize).TotalSeconds; 163 | var secondsLeft = TimeSpan.FromMilliseconds(Constants.LoadCoolDownTimeout).TotalSeconds - secondsSinceLastNewSize; 164 | Console.WriteLine("No new requests for {0} seconds. Waiting another {1}s to finish", secondsSinceLastNewSize, secondsLeft); 165 | 166 | if (secondsLeft < 0) 167 | { 168 | break; 169 | } 170 | } 171 | 172 | Console.WriteLine(testProgressString); 173 | await Task.Delay(1000); 174 | } 175 | catch (Exception e) 176 | { 177 | Console.WriteLine(e); 178 | } 179 | } 180 | } 181 | } 182 | 183 | protected override IDictionary CurrentTestProgress() 184 | { 185 | var testProgressData = base.CurrentTestProgress() ?? new Dictionary(); 186 | testProgressData.Add("Success", _totalSuccessRequestsPerSecond.ToString()); 187 | testProgressData.Add("Failed", _totalFailedRequestsPerSecond.ToString()); 188 | testProgressData.Add("Timeout", _totalTimedOutRequestsPerSecond.ToString()); 189 | testProgressData.Add("Active", _totalActiveRequests.ToString()); 190 | testProgressData.Add("AvgLatency(ms)", _responseTimes.IsEmpty ? 0.ToString() : _responseTimes.Average().ToString()); 191 | //reset values 192 | ResetHttpCounters(); 193 | 194 | return testProgressData; 195 | } 196 | 197 | private void ResetHttpCounters() 198 | { 199 | int t; 200 | while (!_responseTimes.IsEmpty) 201 | { 202 | _responseTimes.TryTake(out t); 203 | } 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/BaseTriggers/QueueTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using ServerlessBenchmark.ServerlessPlatformControllers; 8 | 9 | namespace ServerlessBenchmark.TriggerTests.BaseTriggers 10 | { 11 | public abstract class QueueTriggerTest:StorageTriggerTest 12 | { 13 | protected string SourceQueue { get; set; } 14 | protected string TargetQueue { get; set; } 15 | 16 | protected QueueTriggerTest(string functionName, string[] messages, string sourceQueue, string targetQueue):base(functionName, messages) 17 | { 18 | SourceQueue = sourceQueue; 19 | TargetQueue = targetQueue; 20 | } 21 | 22 | protected override List CleanUpStorageResources() 23 | { 24 | List cloudPlatformResponses = null; 25 | try 26 | { 27 | cloudPlatformResponses = new List 28 | { 29 | {CloudPlatformController.DeleteMessages(new CloudPlatformRequest() {Source = SourceQueue})}, 30 | {CloudPlatformController.DeleteMessages(new CloudPlatformRequest() {Source = TargetQueue})} 31 | }; 32 | } 33 | catch (Exception e) 34 | { 35 | var webException = e.InnerException as WebException; 36 | if (webException != null) 37 | { 38 | if (webException.Status == WebExceptionStatus.ProtocolError && webException.Message.Contains("400")) 39 | { 40 | throw new Exception(String.Format("Error: 404 when deleting message from queue. Check that queues exist: {0} {1}", SourceQueue, TargetQueue)); 41 | } 42 | } 43 | throw; 44 | } 45 | return cloudPlatformResponses; 46 | } 47 | 48 | protected override string StorageType 49 | { 50 | get { return "Queue"; } 51 | } 52 | 53 | protected async override Task VerifyTargetDestinationStorageCount(int expectedCount) 54 | { 55 | return await VerifyQueueMessagesExistInTargetQueue(expectedCount); 56 | } 57 | 58 | protected override async Task UploadItems(IEnumerable items) 59 | { 60 | await UploadMessagesAsync(items); 61 | } 62 | 63 | private async Task UploadMessagesAsync(IEnumerable messages) 64 | { 65 | await CloudPlatformController.EnqueueMessagesAsync(new CloudPlatformRequest() 66 | { 67 | Key = Guid.NewGuid().ToString(), 68 | Source = SourceQueue, 69 | Data = new Dictionary() 70 | { 71 | {Constants.Message, messages} 72 | } 73 | }); 74 | } 75 | 76 | protected override Task TestCoolDown() 77 | { 78 | return Task.FromResult(true); 79 | } 80 | 81 | private async Task VerifyQueueMessagesExistInTargetQueue(int expected) 82 | { 83 | IEnumerable messages; 84 | var lastCountSeen = -1; 85 | int count = 0; 86 | DateTime lastTimeCountChanged = new DateTime(); 87 | var timeout = TimeSpan.FromSeconds(45); 88 | var startTime = DateTime.UtcNow; 89 | do 90 | { 91 | var taskMesagesResponse = await CloudPlatformController.DequeueMessagesAsync(new CloudPlatformRequest() 92 | { 93 | Source = TargetQueue 94 | }); 95 | messages = (IEnumerable) taskMesagesResponse.Data; 96 | count += messages == null ? 0 : messages.Count(); 97 | Console.WriteLine("Destination Messages - Number Of Messages: {0}", count); 98 | Thread.Sleep(1 * 1000); 99 | if (count != lastCountSeen) 100 | { 101 | lastCountSeen = count; 102 | lastTimeCountChanged = DateTime.UtcNow; 103 | } 104 | 105 | if ((startTime - lastTimeCountChanged) > timeout) 106 | { 107 | Console.WriteLine("Waiting for destination queue to reach expected count timed out: {0}/{1}", count, ExpectedExecutionCount); 108 | break; 109 | } 110 | } while (count < expected); 111 | return true; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /ServerlessBenchmark/TriggerTests/BaseTriggers/StorageTriggerTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Threading.Tasks; 7 | using ServerlessBenchmark.PerfResultProviders; 8 | using ServerlessBenchmark.ServerlessPlatformControllers; 9 | 10 | namespace ServerlessBenchmark.TriggerTests.BaseTriggers 11 | { 12 | public abstract class StorageTriggerTest : FunctionTest 13 | { 14 | protected abstract string StorageType { get; } 15 | protected override sealed IEnumerable SourceItems { get; set; } 16 | protected abstract List CleanUpStorageResources(); 17 | protected abstract Task VerifyTargetDestinationStorageCount(int expectedCount); 18 | protected abstract bool Setup(); 19 | protected abstract Task UploadItems(IEnumerable items); 20 | protected abstract override ICloudPlatformController CloudPlatformController { get; } 21 | protected abstract override PerfResultProvider PerfmormanceResultProvider { get; } 22 | 23 | protected StorageTriggerTest(string functionName, string[] items):base(functionName) 24 | { 25 | FunctionName = functionName; 26 | SourceItems = items.ToList(); 27 | } 28 | 29 | protected override bool TestSetupWithRetry() 30 | { 31 | Console.WriteLine("{0} trigger tests - setup", StorageType); 32 | bool successfulSetup; 33 | try 34 | { 35 | Console.WriteLine("Deleting storage items"); 36 | var cloudPlatformResponses = CleanUpStorageResources(); 37 | var undoneJobs = 38 | cloudPlatformResponses.Where( 39 | response => response != null && response.HttpStatusCode != HttpStatusCode.OK); 40 | successfulSetup = !undoneJobs.Any() && Setup(); 41 | } 42 | catch (Exception e) 43 | { 44 | throw new Exception(String.Format("Could not setup Test"), e); 45 | } 46 | return successfulSetup; 47 | } 48 | 49 | protected async override Task TestWarmup() 50 | { 51 | Console.WriteLine("{0} Trigger Warmup - Starting", StorageType); 52 | 53 | var sw = Stopwatch.StartNew(); 54 | 55 | await UploadItems(new[] { SourceItems.First() }); 56 | 57 | Console.WriteLine("{0} Trigger Warmup - Verify test", StorageType); 58 | 59 | bool isWarmUpSuccess = await VerifyTargetDestinationStorageCount(1); 60 | 61 | sw.Stop(); 62 | 63 | Console.WriteLine("{0} Trigger Warmup - Clean Up", StorageType); 64 | 65 | TestSetupWithRetry(); 66 | 67 | Console.WriteLine(isWarmUpSuccess ? "Warmup - Done!" : "Warmup - Done with failures"); 68 | Console.WriteLine("{1} Trigger Warmup - Elapsed Time: {0}ms", sw.ElapsedMilliseconds, StorageType); 69 | } 70 | 71 | protected async override Task PreReportGeneration(DateTime testStartTime, DateTime testEndTime) 72 | { 73 | var expectedDestinationBlobContainerCount = ExpectedExecutionCount; 74 | await VerifyTargetDestinationStorageCount(expectedDestinationBlobContainerCount); 75 | } 76 | 77 | protected override async Task Load(IEnumerable requestItems) 78 | { 79 | await UploadItems(requestItems); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /ServerlessBenchmark/Utility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using Microsoft.WindowsAzure.Storage; 6 | using Microsoft.WindowsAzure.Storage.Table; 7 | using ServerlessBenchmark.PerfResultProviders; 8 | 9 | namespace ServerlessBenchmark 10 | { 11 | public class Utility 12 | { 13 | /// 14 | /// Delete Azure Function Logs from an Azure storage account given the storage connection string. 15 | /// 16 | /// 17 | /// 18 | /// 19 | public static bool RemoveAzureFunctionLogs(string functionName, string storageConnectionString) 20 | { 21 | if (!string.IsNullOrEmpty(storageConnectionString)) 22 | { 23 | var operationContext = new OperationContext(); 24 | var storageAccount = CloudStorageAccount.Parse(storageConnectionString); 25 | var tableClient = storageAccount.CreateCloudTableClient(); 26 | var logs = FunctionLogs.GetAzureFunctionLogs(functionName); 27 | var table = tableClient.GetTableReference(Constants.AzureFunctionLogTableName); 28 | var partitions = logs.GroupBy(log => log.PartitionKey); 29 | var executionLogsCount = logs.Count(log => log.PartitionKey.Equals(Constants.AzureFunctionLogExecutionPartitionKey, 30 | StringComparison.CurrentCultureIgnoreCase)); 31 | var count = 0; 32 | const int batchLimit = 100; 33 | IList deleteResults; 34 | 35 | foreach (var partition in partitions) 36 | { 37 | var tb = new TableBatchOperation(); 38 | var logCount = partition.Count(); 39 | while (logCount > 0) 40 | { 41 | var logPool = partition.Skip(count); 42 | 43 | //azure storage can only process 100 operations at any given time 44 | var selectedLogs = logPool.Take(batchLimit).ToList(); 45 | selectedLogs.ForEach(log => tb.Add(TableOperation.Delete(log))); 46 | try 47 | { 48 | deleteResults = table.ExecuteBatch(tb, null, operationContext); 49 | tb.Clear(); 50 | } 51 | catch (Exception e) 52 | { 53 | deleteResults = new List(); 54 | Console.WriteLine("--ERROR-- Could not delete logs. {0}", e); 55 | } 56 | 57 | var deletedLogsCount = deleteResults.Count(result => result.HttpStatusCode == 204); 58 | count += deletedLogsCount; 59 | Console.WriteLine("Deleted {0}/{1} logs", count, executionLogsCount); 60 | 61 | logCount = logCount - selectedLogs.Count; 62 | } 63 | } 64 | 65 | return true; 66 | } 67 | return false; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /ServerlessBenchmark/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ServerlessTestOrchestrator/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ServerlessTestOrchestrator/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using MiniCommandLineHelper; 5 | using SampleUsages; 6 | using ServerlessBenchmark; 7 | using ServerlessBenchmark.LoadProfiles; 8 | using ServerlessBenchmark.TriggerTests; 9 | 10 | namespace ServerlessTestOrchestrator 11 | { 12 | public class Program : CmdHelper 13 | { 14 | public new static void Main(string[] args) 15 | { 16 | var p = new Program(); 17 | ((CmdHelper)p).Main(args); 18 | } 19 | 20 | [Command] 21 | [CommandLineAttribute("TestScenario ")] 22 | public void RunScenario(string functionName, string platform, string language, string trigger, string type, string loadType) 23 | { 24 | TriggerType triggerType; 25 | TriggerType.TryParse(type, out triggerType); 26 | Language languageType; 27 | Language.TryParse(language, out languageType); 28 | Platorm platformType; 29 | PlatformID.TryParse(platform, out platformType); 30 | FunctionType functionType; 31 | FunctionType.TryParse(type, out functionType); 32 | 33 | var test = new TestDescription 34 | { 35 | FunctionName = functionName, 36 | Trigger = triggerType, 37 | Language = languageType, 38 | Platform = platformType, 39 | Type = functionType 40 | }; 41 | 42 | var testTask = test.GenerateTestTask(); 43 | var load = test.GenerateTestLoadProfile(); 44 | var perfResult = testTask.RunAsync(load).Result; 45 | 46 | //print perf results 47 | var originalColor = Console.ForegroundColor; 48 | Console.ForegroundColor = ConsoleColor.Green; ; 49 | Console.WriteLine(perfResult); 50 | Console.ForegroundColor = originalColor; 51 | 52 | Console.ReadKey(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ServerlessTestOrchestrator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServerlessTestOrchestrator")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServerlessTestOrchestrator")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("98a59127-da0c-4693-85cf-2262d75733ed")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ServerlessTestOrchestrator/ServerlessTestOrchestrator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {98A59127-DA0C-4693-85CF-2262D75733ED} 8 | Exe 9 | Properties 10 | ServerlessTestOrchestrator 11 | ServerlessTestOrchestrator 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | {600ba962-07ea-46ec-b8f5-9bc5933c5533} 59 | MiniCommandLineHelper 60 | 61 | 62 | {582cc16b-6c75-494b-b27f-7a769dec0c30} 63 | ServerlessBenchmark 64 | 65 | 66 | 67 | 74 | -------------------------------------------------------------------------------- /ServerlessTestOrchestrator/TestDescription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using ServerlessBenchmark.LoadProfiles; 5 | using ServerlessBenchmark.TriggerTests; 6 | using ServerlessTestOrchestrator; 7 | using ServerlessTestOrchestrator.TestScenarios; 8 | 9 | namespace SampleUsages 10 | { 11 | internal class TestDescription 12 | { 13 | private const int InputObjectsCount = 1000; 14 | 15 | public string FunctionName { get; set; } 16 | 17 | public Platorm Platform { get; set; } 18 | 19 | public Language Language { get; set; } 20 | 21 | public TriggerType Trigger { get; set; } 22 | 23 | public FunctionType Type { get; set; } 24 | 25 | public string ResolveFolderName() 26 | { 27 | return string.Format( 28 | "{0}-{1}-{2}", 29 | Trigger, 30 | Language, 31 | Type); 32 | } 33 | 34 | public IFunctionsTest GenerateTestTask() 35 | { 36 | ITestScenario scenario = null; 37 | 38 | switch (this.Platform) 39 | { 40 | case Platorm.AzureOnly: 41 | switch (this.Trigger) 42 | { 43 | case TriggerType.Blob: 44 | scenario = new AzureBlobTestScenario(); 45 | break; 46 | case TriggerType.Queue: 47 | throw new NotImplementedException(); 48 | case TriggerType.Http: 49 | throw new NotImplementedException(); 50 | default: 51 | throw new ArgumentException("Unknown trigger type " + this.Trigger); 52 | } 53 | 54 | break; 55 | case Platorm.AmazonOnly: 56 | throw new NotImplementedException(); 57 | case Platorm.AzureAnyAmazon: 58 | throw new NotImplementedException(); 59 | } 60 | 61 | scenario.PrepareData(InputObjectsCount); 62 | return scenario.GetBenchmarkTest(FunctionName); 63 | } 64 | 65 | internal TriggerTestLoadProfile GenerateTestLoadProfile() 66 | { 67 | // TODO implement different load types 68 | return new LinearLoad(InputObjectsCount, 1); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ServerlessTestOrchestrator/TestScenarioOrchestrator.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace SampleUsages 3 | { 4 | public enum Platorm 5 | { 6 | AzureAnyAmazon, 7 | AzureOnly, 8 | AmazonOnly 9 | } 10 | 11 | public enum Language 12 | { 13 | NodeJs 14 | } 15 | 16 | public enum TriggerType 17 | { 18 | Queue, 19 | Blob, 20 | Http 21 | } 22 | 23 | public enum FunctionType 24 | { 25 | CPUIntensive, 26 | HighMemory, 27 | LowUsage 28 | } 29 | 30 | public enum LoadType 31 | { 32 | Steady, 33 | Various, 34 | Peek 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ServerlessTestOrchestrator/TestScenarios/AzureBlobTestScenario.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.IO; 3 | using ServerlessBenchmark.TriggerTests; 4 | 5 | namespace ServerlessTestOrchestrator.TestScenarios 6 | { 7 | internal class AzureBlobTestScenario : ITestScenario 8 | { 9 | private int _testObjectsCount; 10 | 11 | public void PrepareData(int testObjectsCount) 12 | { 13 | _testObjectsCount = testObjectsCount; 14 | } 15 | 16 | public IFunctionsTest GetBenchmarkTest(string functionName) 17 | { 18 | var defaultContainerName = "mycontainer"; 19 | var defaultResultContainer = "myresultcontainer"; 20 | var blobInputTempPath = "temp/"; 21 | PrepareBlobInput(blobInputTempPath); 22 | var blobs = Directory.GetFiles(blobInputTempPath); 23 | return new AzureBlobTriggerTest(functionName, blobs, defaultContainerName, defaultResultContainer); 24 | } 25 | 26 | private void PrepareBlobInput(string blobInputTempPath) 27 | { 28 | for (var i = 0; i < _testObjectsCount; ++i) 29 | { 30 | var path = string.Format("{0}{1}.txt", blobInputTempPath, i); 31 | Directory.CreateDirectory(blobInputTempPath); 32 | var file = new System.IO.StreamWriter(path); 33 | // TODO: add content of the file from Blob-*-* directory 34 | file.WriteLine("150"); 35 | file.Close(); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ServerlessTestOrchestrator/TestScenarios/ITestScenario.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using ServerlessBenchmark.TriggerTests; 7 | 8 | namespace ServerlessTestOrchestrator 9 | { 10 | interface ITestScenario 11 | { 12 | void PrepareData(int testObjectCount); 13 | IFunctionsTest GetBenchmarkTest(string functionName); 14 | } 15 | } 16 | --------------------------------------------------------------------------------