Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DiagnosticScenarios #1378

Merged
merged 9 commits into from
Sep 6, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using System.Threading;

namespace testwebapi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class DiagScenarioController : ControllerBase
{
var o1 = new object();
var o2 = new object();

private static Processor p = new Processor();

[HttpGet]
[Route("deadlock/")]
public ActionResult<string> deadlock()
{
(new System.Threading.Thread(() => {
DeadlockFunc();
})).Start();

Thread.Sleep(5000);

var threads = new Thread[300];
for(int i = 0; i < 300; i++)
{
(threads[i] = new Thread(() => {
lock (o1) {Thread.Sleep(100);}
})).Start();
}

foreach(Thread thread in threads)
{
thread.Join();
}

return "success:deadlock";
}

private void DeadlockFunc()
{
lock (o1)
{
(new Thread(() => {
lock (o2) { Monitor.Enter(o1); }
})).Start();

Thread.Sleep(2000);
Monitor.Enter(o2);
}
}

[HttpGet]
[Route("memspike/{seconds}")]
public ActionResult<string> memspike(int seconds)
{
var watch = new Stopwatch();
watch.Start();

while(true)
{
p = new Processor();
watch.Stop();
if(watch.ElapsedMilliseconds > seconds*1000)
break;
watch.Start();

int it = (2000 * 1000);
for(int i = 0; i < it; i++)
{
p.ProcessTransaction(new Customer(Guid.NewGuid().ToString()));
}

Thread.Sleep(5000); // Sleep for 5 seconds before cleaning up

// Cleanup
p = null;

// Call GC.Collect twice
GC.Collect();
GC.Collect();
sdmaclea marked this conversation as resolved.
Show resolved Hide resolved

Thread.Sleep(5000); // Sleep for 5 seconds before spiking memory again
}
return "success:memspike";
}

[HttpGet]
[Route("memleak/{kb}")]
public ActionResult<string> memleak(int kb)
{
int it = (kb * 1000) / 100;
for(int i = 0; i < it; i++)
{
p.ProcessTransaction(new Customer(Guid.NewGuid().ToString()));
}

return "success:memleak";
}

[HttpGet]
[Route("exception")]
public ActionResult<string> exception()
{
throw new Exception("bad, bad code");
}


[HttpGet]
[Route("highcpu/{milliseconds}")]
public ActionResult<string> highcpu(int milliseconds)
{
var watch = new Stopwatch();
watch.Start();

while (true)
{
watch.Stop();
if(watch.ElapsedMilliseconds > milliseconds)
break;
watch.Start();
}

return "success:highcpu";
}
}

class Customer
{
private string id;

public Customer(string id)
{
this.id = id;
}
}

class CustomerCache
{
private List<Customer> cache = new List<Customer>();

public void AddCustomer(Customer c)
{
cache.Add(c);
}
}

class Processor
{
private CustomerCache cache = new CustomerCache();

public void ProcessTransaction(Customer customer)
{
cache.AddCustomer(customer);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace DiagnosticScenarios.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}

// GET api/values/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "value";
}

// POST api/values
[HttpPost]
public void Post([FromBody] string value)
{
}

// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] string value)
{
}

// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}
11 changes: 11 additions & 0 deletions core/diagnostics/DiagnosticScenarios/DiagnosticScenarios.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview5-19227-01" />
</ItemGroup>

</Project>
26 changes: 26 additions & 0 deletions core/diagnostics/DiagnosticScenarios/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace DiagnosticScenarios
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:26127",
"sslPort": 44359
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"DiagnosticScenarios": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/values",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
57 changes: 57 additions & 0 deletions core/diagnostics/DiagnosticScenarios/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace DiagnosticScenarios
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddNewtonsoftJson();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
10 changes: 10 additions & 0 deletions core/diagnostics/DiagnosticScenarios/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
32 changes: 32 additions & 0 deletions core/diagnostics/DiagnosticScenarios/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# DiagnosticScenarios sample debug target

sdmaclea marked this conversation as resolved.
Show resolved Hide resolved
This sample is for the [diagnostics tutorials](https://docs.microsoft.com/dotnet/core/diagnostics/tutorial/diagnostic-scenarios.md) in the .NET Core Guide.
sdmaclea marked this conversation as resolved.
Show resolved Hide resolved

The scenarios are implemented using a `webapi` target with methods that trigger undesirable behaviors for us to diagnose.

## Target methods

### Deadlock

http://localhost:5000/api/diagscenario/deadlock

This method will cause the target to hang and accumulate many threads.

### High CPU usage

http://localhost:5000/api/diagscenario/highcpu/{milliseconds}

The method will cause to target to heavily use the CPU for a duration specified by {milliseconds}.

### Memory leak

http://localhost:5000/api/diagscenario/memleak/{kb}

This method will cause the target to leak memory (amount specified by {kb}).

### Memory usage spike

http://localhost:5000/api/diagscenario/memspike/{seconds}

This method will cause intermittent memory spikes over the specified number of seconds. Memory will go from base line to spike and back to baseline several times.