diff --git a/README.md b/README.md index a3879542702..37c9b5b8712 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,21 @@ Now you can run tests: python run-tests.py -s server-ip -c client-ip -i "C:\Users\Administrator\Desktop\client.key" --max-threads 2 --duration 30 --sleep 5 --name win --test aspnet --type all +### SQL Server on Windows Instructions + +Server installation scripts for Windows Server 2012 with SQL Server 2012 Standard on Amazon EC2. + +Instructions: + +* Create an instance from the [Windows Server 2012 RTM English 64-bit SQL 2012 Standard](https://aws.amazon.com/amis/amazon-ebs-backed-windows-server-2012-rtm-english-64-bit-sql-2012-standard) image on Amazon EC2 +* Connect to it via Remote Desktop +* Run a `Command Prompt` as Administrator +* Enter `powershell -ExecutionPolicy Bypass -Command "iex (New-Object Net.WebClient).DownloadString('https://raw.github.com/TechEmpower/FrameworkBenchmarks/master/setup-sqlserver-bootstrap.ps1')"` +* This will configure SQL Server, the Windows Firewall, and populate the database. + +Now, when running `python run-tests.py`, just add `-d `. This works for the (Windows Server-based) `aspnet-sqlserver-raw` and `aspnet-sqlserver-entityframework` tests. + + ## Result Files After a test run, the directory ~/FrameworkBenchmarks/results/machine-name/timestamp will contains all the result files. In this folder are four files: three CSV files, one for each of the test types (json, db, query), and a single results.json file that contains all the results as well as some additional information. The results.json file is what we use to drive our blog post, and may or may not be useful to you. There are three subdirectories: one for each of the test types (json, db, query), each of these directories contain the raw weighttp results for each framework. diff --git a/aspnet/README.md b/aspnet/README.md index 1712d16a234..29b285d1be6 100644 --- a/aspnet/README.md +++ b/aspnet/README.md @@ -36,6 +36,7 @@ * Npgsql 2.0.12 ([custom build](https://github.com/pdonald/Npgsql2)) * Entity Framework 6.0.0-alpha3 * Mongo C# Driver 1.8.1 +* SqlClient Data Provider for SQL Server **Developer Tools** diff --git a/aspnet/benchmark_config b/aspnet/benchmark_config index 74b01e8dc3a..cd9e36577dd 100644 --- a/aspnet/benchmark_config +++ b/aspnet/benchmark_config @@ -38,6 +38,16 @@ "port": 8080, "sort": 93 }, + "sqlserver-raw": { + "setup_file": "setup_iis", + "os": "nt", + "db_url": "/ado/sqlserver", + "query_url": "/ado/sqlserver?queries=", + "fortune_url": "/ado/sqlserver/fortunes", + "update_url": "/ado/sqlserver/update?queries=", + "port": 8080, + "sort": 94 + }, "mysql-entityframework": { "setup_file": "setup_iis", "os": "nt", @@ -46,7 +56,7 @@ "fortune_url": "/entityframework/mysql/fortunes", "update_url": "/entityframework/mysql/update?queries=", "port": 8080, - "sort": 94 + "sort": 95 }, "postgresql-entityframework": { "setup_file": "setup_iis", @@ -56,7 +66,17 @@ "fortune_url": "/entityframework/postgresql/fortunes", "update_url": "/entityframework/postgresql/update?queries=", "port": 8080, - "sort": 95 + "sort": 96 + }, + "sqlserver-entityframework": { + "setup_file": "setup_iis", + "os": "nt", + "db_url": "/entityframework/sqlserver", + "query_url": "/entityframework/sqlserver?queries=", + "fortune_url": "/entityframework/sqlserver/fortunes", + "update_url": "/entityframework/sqlserver/update?queries=", + "port": 8080, + "sort": 97 }, "mono": { "setup_file": "setup_nginx", diff --git a/aspnet/src/Application.cs b/aspnet/src/Application.cs index 7b7f557b87b..07747b081af 100644 --- a/aspnet/src/Application.cs +++ b/aspnet/src/Application.cs @@ -45,7 +45,7 @@ private void Routes() name: "WithProviders", url: "{controller}/{providerName}/{action}", defaults: new { action = "Index" }, - constraints: new { controller = "ado|entityframework", providerName = "mysql|postgresql" } + constraints: new { controller = "ado|entityframework", providerName = "mysql|postgresql|sqlserver" } ); RouteTable.Routes.MapRoute( diff --git a/aspnet/src/Controllers/AdoController.cs b/aspnet/src/Controllers/AdoController.cs index d27985ad8a6..8dfe14295f9 100644 --- a/aspnet/src/Controllers/AdoController.cs +++ b/aspnet/src/Controllers/AdoController.cs @@ -143,12 +143,16 @@ public ActionResult Update(string providerName, int? queries) if (world == null) continue; + DbParameter idUpdateParameter = updateCommand.CreateParameter(); + idUpdateParameter.ParameterName = "@ID"; + idUpdateParameter.Value = randomID; + DbParameter numberParameter = updateCommand.CreateParameter(); numberParameter.ParameterName = "@Number"; numberParameter.Value = randomNumber; updateCommand.Parameters.Clear(); - updateCommand.Parameters.Add(idParameter); + updateCommand.Parameters.Add(idUpdateParameter); updateCommand.Parameters.Add(numberParameter); updateCommand.ExecuteNonQuery(); diff --git a/aspnet/src/Web.config b/aspnet/src/Web.config index 94bfc6ff714..a30dce4812d 100644 --- a/aspnet/src/Web.config +++ b/aspnet/src/Web.config @@ -9,6 +9,7 @@ + @@ -16,6 +17,7 @@ + @@ -23,6 +25,7 @@ + diff --git a/config/create-sqlserver-login-and-database.sql b/config/create-sqlserver-login-and-database.sql new file mode 100644 index 00000000000..700b7c6f4b0 --- /dev/null +++ b/config/create-sqlserver-login-and-database.sql @@ -0,0 +1,28 @@ +-- This SQL Server T-SQL script creates the database user and hello_world database. +-- +-- To run this script, login to an administrator account in Windows, open a command prompt and run: +-- +-- "%ProgramFiles%\Microsoft SQL Server\110\Tools\binn\sqlcmd.exe" -i +-- + +IF EXISTS (SELECT * FROM sys.server_principals WHERE name = 'benchmarkdbuser') + DROP LOGIN benchmarkdbuser +GO + +-- This password has mixed-case and a number to satisfy the Windows password policy +CREATE LOGIN benchmarkdbuser WITH PASSWORD = 'B3nchmarkDBPass' +GO + +IF EXISTS(SELECT * FROM SYS.DATABASES WHERE NAME='hello_world') + DROP DATABASE hello_world +GO + +CREATE DATABASE hello_world +GO +USE hello_world +GO + +-- Give this user total power over the database +CREATE USER benchmarkdbuser FOR LOGIN benchmarkdbuser +EXEC sp_addrolemember 'db_owner', 'benchmarkdbuser' +GO diff --git a/config/create-sqlserver.sql b/config/create-sqlserver.sql new file mode 100644 index 00000000000..9b53168183c --- /dev/null +++ b/config/create-sqlserver.sql @@ -0,0 +1,55 @@ +-- This SQL Server T-SQL script creates and populates the World and Fortune tables. +-- +-- To run this script, make sure that you've already run create-sqlserver-login-and-database.sql +-- to create the database user and database, then open a command prompt and run: +-- +-- "%ProgramFiles%\Microsoft SQL Server\110\Tools\binn\sqlcmd.exe" -U benchmarkdbuser -P B3nchmarkDBPass -d hello_world -i + +IF OBJECT_ID('World', 'U') IS NOT NULL + DROP TABLE World +GO + +CREATE TABLE World ( + id int NOT NULL IDENTITY PRIMARY KEY, + randomNumber int NOT NULL default 0 +) +GO + +-- Populate World table +DECLARE @RowCount INT +DECLARE @Random INT +SET @RowCount = 0 + +WHILE @RowCount < 10000 +BEGIN + SELECT @Random = ((10000 + 1) - 1) * RAND() + 1 + INSERT INTO World (randomNumber) VALUES (@Random) + SET @RowCount = @RowCount + 1 +END + +GO + +IF OBJECT_ID('Fortune', 'U') IS NOT NULL + DROP TABLE Fortune +GO + +-- Note that this uses nvarchar to make sure that the column is Unicode. +CREATE TABLE Fortune ( + id int NOT NULL IDENTITY PRIMARY KEY, + message nvarchar(2048) NOT NULL +) +GO + +INSERT INTO Fortune (message) VALUES (N'fortune: No such file or directory'); +INSERT INTO Fortune (message) VALUES (N'A computer scientist is someone who fixes things that aren''t broken.'); +INSERT INTO Fortune (message) VALUES (N'After enough decimal places, nobody gives a damn.'); +INSERT INTO Fortune (message) VALUES (N'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1'); +INSERT INTO Fortune (message) VALUES (N'A computer program does what you tell it to do, not what you want it to do.'); +INSERT INTO Fortune (message) VALUES (N'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen'); +INSERT INTO Fortune (message) VALUES (N'Any program that runs right is obsolete.'); +INSERT INTO Fortune (message) VALUES (N'A list is only as strong as its weakest link. — Donald Knuth'); +INSERT INTO Fortune (message) VALUES (N'Feature: A bug with seniority.'); +INSERT INTO Fortune (message) VALUES (N'Computers make very fast, very accurate mistakes.'); +INSERT INTO Fortune (message) VALUES (N''); +INSERT INTO Fortune (message) VALUES (N'フレームワークのベンチマーク'); +GO diff --git a/setup-sqlserver-bootstrap.ps1 b/setup-sqlserver-bootstrap.ps1 new file mode 100644 index 00000000000..4e283ca6c90 --- /dev/null +++ b/setup-sqlserver-bootstrap.ps1 @@ -0,0 +1,25 @@ +# To download and run this script, open an elevated Command Prompt and then run: +# +# powershell -ExecutionPolicy Bypass -Command "iex (New-Object Net.WebClient).DownloadString('https://raw.github.com/TechEmpower/FrameworkBenchmarks/master/setup-sqlserver-bootstrap.ps1')" + +$basedir = "C:\FrameworkBenchmarks" +$rawRepo = "https://raw.github.com/TechEmpower/FrameworkBenchmarks/master" + +$config_url = $basedir + "/config" +$config_local = $basedir + "\config" +$setup_sqlserver_url = $rawRepo + "/setup-sqlserver.ps1" +$setup_sqlserver_local = $basedir + "\setup-sqlserver.ps1" +$create_sqlserver_login_and_database_url = $config_url + "/create-sqlserver-login-and-database.sql" +$create_sqlserver_login_and_database_local = $config_local + "/create-sqlserver-login-and-database.sql" +$create_sqlserver_url = $config_url + "/create-sqlserver.sql" +$create_sqlserver_local = $config_local + "/create-sqlserver.sql" + +Write-Host "Creating directory: $config`n" +New-Item -Path $config_local -Type Directory -Force | Out-Null + +Write-Host "Downloading setup files...`n" +(New-Object System.Net.WebClient).DownloadFile($setup_sqlserver_url, $setup_sqlserver_local) +(New-Object System.Net.WebClient).DownloadFile($create_sqlserver_login_and_database_url, $create_sqlserver_login_and_database_local) +(New-Object System.Net.WebClient).DownloadFile($create_sqlserver_url, $create_sqlserver_local) + +powershell -ExecutionPolicy Bypass -File $setup_sqlserver_local diff --git a/setup-sqlserver.ps1 b/setup-sqlserver.ps1 new file mode 100644 index 00000000000..f84df471e50 --- /dev/null +++ b/setup-sqlserver.ps1 @@ -0,0 +1,91 @@ +# This script downloads and installs SQL Server and opens it on port 1433. +# +# To run this script, run an elevated Command Prompt and enter: +# +# powershell -ExecutionPolicy Bypass -File + +$basedir = "C:\FrameworkBenchmarks" +$workdir = "$basedir\installs" +New-Item -Path $workdir -Type directory -Force | Out-Null + +If (-Not (Get-Service | ? Name -Eq "MSSQLSERVER")) { + + Write-Host "Could not find default SQL Server instance, MSSQLSERVER." + Write-Host "Downloading SQL Server (several GBs)..." + + # URLs from http://www.microsoft.com/en-us/download/details.aspx?id=35575 + + $sqlserver_exe_url = "http://download.microsoft.com/download/3/B/D/3BD9DD65-D3E3-43C3-BB50-0ED850A82AD5/SQLServer2012SP1-FullSlipstream-x64-ENU.exe" + $sqlserver_exe_local = "$workdir\SQLServer2012SP1-FullSlipstream-x64-ENU.exe" + (New-Object System.Net.WebClient).DownloadFile($sqlserver_exe_url, $sqlserver_exe_local) + + $sqlserver_box_url = "http://download.microsoft.com/download/3/B/D/3BD9DD65-D3E3-43C3-BB50-0ED850A82AD5/SQLServer2012SP1-FullSlipstream-x64-ENU.box" + $sqlserver_box_local = "$workdir\SQLServer2012SP1-FullSlipstream-x64-ENU.box" + (New-Object System.Net.WebClient).DownloadFile($sqlserver_box_url, $sqlserver_box_local) + + Write-Host "Installing SQL Server..." + + # Install only the SQL Server database engine. + # Use a default instance name. + # Make %COMPUTERNAME%\Administrators have administrative rights. + + # The following is not used because this is done in PowerShell below. + # /securitymode=SQL /sapwd=S3cr3tS3cr3t /TCPENABLED=1 + # Allow Windows Authentication or old-style SQL authentication. + # The password of the sa account is specified. + # SQL Server will be listening on TCP port 1433. + # + Start-Process "$sqlserver_exe_local" "/q /action=install /features=SQLEngine /INSTANCENAME=MSSQLSERVER /SQLSYSADMINACCOUNTS=Administrators /IACCEPTSQLSERVERLICENSETERMS" -Wait +} + +# In case we just installed SQL Server and the environment variables haven't been refreshed, manually +# refresh PSModulePath so that Import-Module sqlps will work. + +$env:PSModulePath = [Environment]::GetEnvironmentVariable("PSModulePath", [System.EnvironmentVariableTarget]::Machine) + +Import-Module sqlps + +Write-Host "Setting SQL Server to start on boot..." + +Set-Service MSSQLSERVER -StartupType Automatic + +Write-Host "Ensuring that SQL Server is started..." + +Start-Service MSSQLSERVER + +Write-Host "Enabling SQL authentication..." + +# Enable SQL authentication +$s = New-Object ('Microsoft.SqlServer.Management.Smo.Server') +$s.Settings.LoginMode = [Microsoft.SqlServer.Management.SMO.ServerLoginMode]::Mixed +$s.Alter() + +Write-Host "Configuring SQL Server to listen on TCP (default port 1433)..." + +# Enable the TCP protocol on the default instance. +$wmi = New-Object ('Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer') +$uri = "ManagedComputer[@Name='" + (Get-Content env:computername) + "']/ ServerInstance[@Name='MSSQLSERVER']/ServerProtocol[@Name='Tcp']" +$Tcp = $wmi.GetSmoObject($uri) +$Tcp.IsEnabled = $true +$Tcp.Alter() + +Write-Host "Restarting SQL Server..." + +Restart-Service -Name MSSQLSERVER + +If (-Not (Get-NetFirewallPortFilter | ? LocalPort -Eq "1433")) { + Write-Host "Opening port 1433 in firewall..." + New-NetFirewallRule -DisplayName "SQL 1433" -Action Allow -Direction Inbound -LocalPort 1433 -Protocol TCP | Out-Null +} else { + Write-Host "Port 1433 is already configured in firewall." +} + +Write-Host "Creating SQL Server login and populated database..." + +# Connect with Windows Authentication, assuming that we have access. +Invoke-Sqlcmd -InputFile "$basedir\config\create-sqlserver-login-and-database.sql" -OutputSqlErrors $True + +# Now that benchmarkdbuser has been created, we can connect with those credentials. +Invoke-Sqlcmd -Username benchmarkdbuser -Password B3nchmarkDBPass -Database hello_world -InputFile "$basedir\config\create-sqlserver.sql" -OutputSqlErrors $True + +Write-Host "Done."