Skip to content

Commit 64712af

Browse files
committed
Initial Commit
1 parent 73c39a2 commit 64712af

34 files changed

Lines changed: 2332 additions & 0 deletions
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
5+
</startup>
6+
<connectionStrings>
7+
<!--<add name="Db" connectionString="Server=tcp:peskount-hktest1.database.windows.net,1433;Database=PowerConsumption;User ID=demovm001@peskount-hktest1;Password=LetAzureIn0_;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"/>-->
8+
<add name="Db" connectionString="Server=.;Database=PowerConsumption;Integrated Security=True"/>
9+
</connectionStrings>
10+
<appSettings>
11+
<add key="insertSPName" value="InsertMeterMeasurement"/> <!--Stored Procedure Name-->
12+
<add key="numberOfTasks" value="50"/> <!--Number of concurrent async tasks that the Data Generator will use-->
13+
<add key="numberOfMeters" value="1000000"/> <!--Number of unique meter Ids-->
14+
<add key="batchSize" value="1000"/> <!--Row Batch Size that every task produces-->
15+
<add key="commandDelay" value="1500"/> <!--Delay between sql commands. You can set this to 0 for max high volume workload-->
16+
<add key="commandTimeout" value="600"/> <!--SQL Command Timeout-->
17+
<add key="enableShock" value="1"/> <!--Flag that turns on/off the data shock. This should be set to 0 for max high volume workload-->
18+
<add key="shockFrequency" value="35000"/> <!--The Frequency that the code sets the commandDelay to 0-->
19+
<add key="shockDuration" value="4000"/> <!--The Duration that the code keeps the commandDelay to 0-->
20+
<add key="rpsFrequency" value="2000"/> <!--How frequently the Data Generator Rows Per Second(RPS) is polled-->
21+
<add key="logFileName" value="log.txt"/> <!--Log File Path-->
22+
<add key="powerBIDesktopPath" value="C:\Program Files\Microsoft Power BI Desktop\bin\PBIDesktop.exe"/><!--PowerBIDesktop.exe path-->
23+
</appSettings>
24+
</configuration>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{BB747094-2CF6-46D2-8E6C-07E27CF0BCAA}</ProjectGuid>
8+
<OutputType>Exe</OutputType>
9+
<AppDesignerFolder>Properties</AppDesignerFolder>
10+
<RootNamespace>ConsoleClient</RootNamespace>
11+
<AssemblyName>ConsoleClient</AssemblyName>
12+
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
13+
<FileAlignment>512</FileAlignment>
14+
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
15+
</PropertyGroup>
16+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17+
<PlatformTarget>AnyCPU</PlatformTarget>
18+
<DebugSymbols>true</DebugSymbols>
19+
<DebugType>full</DebugType>
20+
<Optimize>false</Optimize>
21+
<OutputPath>bin\Debug\</OutputPath>
22+
<DefineConstants>DEBUG;TRACE</DefineConstants>
23+
<ErrorReport>prompt</ErrorReport>
24+
<WarningLevel>4</WarningLevel>
25+
</PropertyGroup>
26+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
27+
<PlatformTarget>AnyCPU</PlatformTarget>
28+
<DebugType>pdbonly</DebugType>
29+
<Optimize>true</Optimize>
30+
<OutputPath>bin\Release\</OutputPath>
31+
<DefineConstants>TRACE</DefineConstants>
32+
<ErrorReport>prompt</ErrorReport>
33+
<WarningLevel>4</WarningLevel>
34+
</PropertyGroup>
35+
<ItemGroup>
36+
<Reference Include="System" />
37+
<Reference Include="System.configuration" />
38+
<Reference Include="System.Core" />
39+
<Reference Include="System.Xml.Linq" />
40+
<Reference Include="System.Data.DataSetExtensions" />
41+
<Reference Include="Microsoft.CSharp" />
42+
<Reference Include="System.Data" />
43+
<Reference Include="System.Net.Http" />
44+
<Reference Include="System.Xml" />
45+
</ItemGroup>
46+
<ItemGroup>
47+
<Compile Include="Program.cs" />
48+
<Compile Include="Properties\AssemblyInfo.cs" />
49+
</ItemGroup>
50+
<ItemGroup>
51+
<None Include="..\App.config">
52+
<Link>App.config</Link>
53+
</None>
54+
<None Include="..\PowerDashboard.pbix">
55+
<Link>Reports\PowerDashboard.pbix</Link>
56+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
57+
</None>
58+
</ItemGroup>
59+
<ItemGroup>
60+
<ProjectReference Include="..\DataGenerator\DataGenerator.csproj">
61+
<Project>{d871b062-06a7-49e3-8bcd-8465b772fc52}</Project>
62+
<Name>DataGenerator</Name>
63+
</ProjectReference>
64+
</ItemGroup>
65+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
66+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
67+
Other similar extension points exist, see Microsoft.Common.targets.
68+
<Target Name="BeforeBuild">
69+
</Target>
70+
<Target Name="AfterBuild">
71+
</Target>
72+
-->
73+
</Project>
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/*----------------------------------------------------------------------------------
2+
Copyright (c) Microsoft Corporation. All rights reserved.
3+
4+
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
5+
EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
6+
OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
7+
----------------------------------------------------------------------------------
8+
The example companies, organizations, products, domain names,
9+
e-mail addresses, logos, people, places, and events depicted
10+
herein are fictitious. No association with any real company,
11+
organization, product, domain name, email address, logo, person,
12+
places, or events is intended or should be inferred.
13+
14+
*/
15+
16+
using System;
17+
using System.IO;
18+
using DataGenerator;
19+
using System.Configuration;
20+
using System.Timers;
21+
using System.Diagnostics;
22+
using System.Collections.Generic;
23+
using System.Linq;
24+
using System.Text;
25+
using System.Threading.Tasks;
26+
27+
/*----------------------------------------------------------------------------------
28+
High Level Scenario:
29+
This code sample demonstrates how a SQL Server 2016 (or higher) memory optimized database could be used to ingest a very high input data rate
30+
and ultimately help improve the performance of applications with this scenario. The code simulates an IoT Smart Grid scenario where multiple
31+
IoT power meters are constantly sending electricity usage measurements to the database.
32+
33+
Details:
34+
This code sample simulates an IoT Smart Grid scenario where multiple IoT power meters are sending electricity usage measurements to a SQL Server memory optimized database.
35+
The Data Generator, that can be started either from the Console or the Windows Form client, produces a data generated spike to simulate a
36+
shock absorber scenario: https://blogs.technet.microsoft.com/dataplatforminsider/2013/09/19/in-memory-oltp-common-design-pattern-high-data-input-rateshock-absorber/.
37+
Every async task in the Data Generator produces a batch of records with random values in order to simulate the data of an IoT power meter.
38+
It then calls a natively compiled stored procedure, that accepts an memory optimized table valued parameter (TVP), to insert the data into an memory optimized SQL Server table.
39+
In addition to the in-memory features, the sample is leveraging System-Versioned Temporal Tables: https://msdn.microsoft.com/en-us/library/dn935015.aspx for building version history,
40+
Clustered Columnstore Index: https://msdn.microsoft.com/en-us/library/dn817827.aspx) for enabling real time operational analytics, and
41+
Power BI: https://powerbi.microsoft.com/en-us/desktop/ for data visualization.
42+
*/
43+
namespace ConsoleClient
44+
{
45+
class Program
46+
{
47+
static SqlDataGenerator dataGenerator;
48+
static string connection;
49+
static string spName;
50+
static string logFileName;
51+
static string powerBIDesktopPath;
52+
static int tasks;
53+
static int meters;
54+
static int batchSize;
55+
static int delay;
56+
static int commandTimeout;
57+
static int shockFrequency;
58+
static int shockDuration;
59+
static int rpsFrequency;
60+
static int enableShock;
61+
static Timer mainTimer = new Timer();
62+
static Timer rpsTimer = new Timer();
63+
static Timer shockTimer = new Timer();
64+
65+
static void Main(string[] args)
66+
{
67+
Init();
68+
dataGenerator = new SqlDataGenerator(connection, spName, commandTimeout, meters, tasks, delay, batchSize, ExceptionCallback);
69+
70+
mainTimer.Elapsed += mainTimer_Tick;
71+
rpsTimer.Elapsed += rpsTimer_Tick;
72+
shockTimer.Elapsed += shockTimer_Tick;
73+
74+
string commandString = string.Empty;
75+
Console.ForegroundColor = ConsoleColor.White;
76+
Console.WriteLine("***********************************************************");
77+
Console.WriteLine("* Data Generator *");
78+
Console.WriteLine("* *");
79+
Console.WriteLine("* Type commands to get started *");
80+
Console.WriteLine("* *");
81+
Console.WriteLine("***********************************************************");
82+
Console.WriteLine("");
83+
84+
// main command cycle
85+
while (!commandString.Equals("Exit"))
86+
{
87+
Console.ResetColor();
88+
Console.WriteLine("Enter command (start | stop | help | report | exit) >");
89+
commandString = Console.ReadLine();
90+
91+
switch (commandString.ToUpper())
92+
{
93+
case "START":
94+
Start();
95+
break;
96+
case "STOP":
97+
Stop();
98+
break;
99+
case "HELP":
100+
Help();
101+
break;
102+
case "REPORT":
103+
Report();
104+
break;
105+
case "EXIT":
106+
Console.WriteLine("Bye!");
107+
return;
108+
default:
109+
Console.ForegroundColor = ConsoleColor.Red;
110+
Console.WriteLine("Invalid command.");
111+
break;
112+
}
113+
}
114+
}
115+
static void ExceptionCallback(int taskId, Exception exception)
116+
{
117+
HandleException(exception, taskId);
118+
}
119+
static void HandleException(Exception exception, int? taskId = null)
120+
{
121+
string ex = taskId?.ToString() + " - " + exception.Message + (exception.InnerException != null ? "\n\nInner Exception\n" + exception.InnerException : "");
122+
123+
Console.WriteLine(ex);
124+
using (StreamWriter w = File.AppendText(logFileName)) { w.WriteLine("\r\n{0}: {1}", DateTime.Now, ex); }
125+
}
126+
static async void Start()
127+
{
128+
try
129+
{
130+
if (!dataGenerator.IsRunning)
131+
{
132+
if(enableShock == 1) mainTimer.Start();
133+
rpsTimer.Start();
134+
135+
await dataGenerator.RunAsync();
136+
}
137+
}
138+
catch (Exception exception) { HandleException(exception); }
139+
}
140+
141+
static async void Stop()
142+
{
143+
try
144+
{
145+
if (dataGenerator.IsRunning)
146+
{
147+
if (enableShock == 1) mainTimer.Stop();
148+
rpsTimer.Stop();
149+
if (enableShock == 1) shockTimer.Stop();
150+
151+
await dataGenerator.StopAsync();
152+
dataGenerator.RpsReset();
153+
}
154+
}
155+
catch (Exception exception) { HandleException(exception); }
156+
}
157+
158+
static void Report()
159+
{
160+
ProcessStartInfo psi = new ProcessStartInfo();
161+
psi.FileName = powerBIDesktopPath;
162+
psi.Arguments = @"Reports\PowerDashboard.pbix";
163+
Process.Start(psi);
164+
}
165+
static void Help()
166+
{
167+
Console.ForegroundColor = ConsoleColor.Green;
168+
Console.WriteLine("");
169+
Console.WriteLine("START - Starts the DataGenerator");
170+
Console.WriteLine("STOP - Stops the DataGenerator");
171+
Console.WriteLine("HELP - Displays this page");
172+
Console.WriteLine("REPORT - Launches the Power BI Report");
173+
Console.WriteLine("EXIT - Closes this program");
174+
Console.WriteLine("");
175+
}
176+
static void Init()
177+
{
178+
try
179+
{
180+
// Read Config Settings
181+
connection = ConfigurationManager.ConnectionStrings["Db"].ConnectionString;
182+
spName = ConfigurationManager.AppSettings["insertSPName"];
183+
logFileName = ConfigurationManager.AppSettings["logFileName"];
184+
powerBIDesktopPath = ConfigurationManager.AppSettings["powerBIDesktopPath"];
185+
tasks = int.Parse(ConfigurationManager.AppSettings["numberOfTasks"]);
186+
meters = int.Parse(ConfigurationManager.AppSettings["numberOfMeters"]);
187+
batchSize = int.Parse(ConfigurationManager.AppSettings["batchSize"]);
188+
delay = int.Parse(ConfigurationManager.AppSettings["commandDelay"]);
189+
commandTimeout = int.Parse(ConfigurationManager.AppSettings["commandTimeout"]);
190+
shockFrequency = int.Parse(ConfigurationManager.AppSettings["shockFrequency"]);
191+
shockDuration = int.Parse(ConfigurationManager.AppSettings["shockDuration"]);
192+
enableShock = int.Parse(ConfigurationManager.AppSettings["enableShock"]);
193+
194+
rpsFrequency = int.Parse(ConfigurationManager.AppSettings["rpsFrequency"]);
195+
196+
// Initialize Timers
197+
mainTimer.Interval = shockFrequency;
198+
shockTimer.Interval = shockDuration;
199+
rpsTimer.Interval = rpsFrequency;
200+
201+
if (batchSize <= 0) throw new SqlDataGeneratorException("The Batch Size cannot be less or equal to zero.");
202+
203+
if (tasks <= 0) throw new SqlDataGeneratorException("Number Of Tasks cannot be less or equal to zero.");
204+
205+
if (delay < 0) throw new SqlDataGeneratorException("Delay cannot be less than zero");
206+
207+
if (meters <= 0) throw new SqlDataGeneratorException("Number Of Meters cannot be less than zero");
208+
209+
if (meters < batchSize * tasks) throw new SqlDataGeneratorException("Number Of Meters cannot be less than (Tasks * BatchSize).");
210+
}
211+
catch (Exception exception) { HandleException(exception); }
212+
}
213+
static void mainTimer_Tick(object sender, ElapsedEventArgs e)
214+
{
215+
if (dataGenerator.IsRunning)
216+
{
217+
dataGenerator.Delay = 0;
218+
shockTimer.Start();
219+
}
220+
}
221+
static void rpsTimer_Tick(object sender, ElapsedEventArgs e)
222+
{
223+
try
224+
{
225+
double rps = dataGenerator.Rps;
226+
if (dataGenerator.IsRunning)
227+
{
228+
if (dataGenerator.RunningTasks == 0) return;
229+
230+
if (rps > 0)
231+
{
232+
Console.SetCursorPosition(0, Console.CursorTop);
233+
Console.Write(string.Format("Rows Per Second (RPS):{0:#,#} ", rps).ToString());
234+
}
235+
}
236+
}
237+
catch (Exception exception) { HandleException(exception); }
238+
}
239+
static void shockTimer_Tick(object sender, ElapsedEventArgs e)
240+
{
241+
Random rand = new Random();
242+
dataGenerator.Delay = rand.Next(1500, 3000);
243+
shockTimer.Stop();
244+
}
245+
}
246+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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("ConsoleClient")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("ConsoleClient")]
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("bb747094-2cf6-46d2-8e6c-07e27cf0bcaa")]
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")]

0 commit comments

Comments
 (0)