public IActionResult Create([FromBody] ServerJob job) { lock (_jobs) { if (job == null || job.Id != 0) { return(BadRequest()); } else if (job.DriverVersion < 1) { return(BadRequest("The driver is not compatible with this server, please update it.")); } else if (job.State != ServerState.New) { return(BadRequest("The job state should be ServerState.New. You are probably using a wrong version of the driver.")); } job.Hardware = Startup.Hardware; job.HardwareVersion = Startup.HardwareVersion; job.OperatingSystem = Startup.OperatingSystem; // Use server-side date and time to prevent issues fron time drifting job.LastDriverCommunicationUtc = DateTime.UtcNow; job = _jobs.Add(job); Response.Headers["Location"] = $"/jobs/{job.Id}"; return(new StatusCodeResult((int)HttpStatusCode.Accepted)); } }
/// <summary> /// Downloads the whole job including the measurements. /// </summary> public async Task <bool> TryUpdateJobAsync() { Log.Verbose($"GET {_serverJobUri} ..."); var response = await _httpClient.GetAsync(_serverJobUri); var responseContent = await response.Content.ReadAsStringAsync(); Log.Verbose($"{(int)response.StatusCode} {response.StatusCode} {responseContent}"); if (response.StatusCode == HttpStatusCode.NotFound || String.IsNullOrEmpty(responseContent)) { return(false); } else { try { Job = JsonConvert.DeserializeObject <ServerJob>(responseContent); } catch { Log.Write($"ERROR while deserializing state on {_serverJobUri}"); return(false); } return(true); } }
private Task WriteJobsToSql(ServerJob serverJob, ClientJob clientJob, DateTime utcNow, string connectionString, string tableName, string path, string session, string description, string dimension, double value) { return(RetryOnExceptionAsync(5, () => WriteResultsToSql( utcNow, connectionString: connectionString, tableName: tableName, scenario: serverJob.Scenario, session: session, description: description, aspnetCoreVersion: serverJob.AspNetCoreVersion, runtimeVersion: serverJob.RuntimeVersion, hardware: serverJob.Hardware.Value, hardwareVersion: serverJob.HardwareVersion, operatingSystem: serverJob.OperatingSystem.Value, scheme: serverJob.Scheme, source: serverJob.Source, webHost: serverJob.WebHost, kestrelThreadCount: serverJob.KestrelThreadCount, clientThreads: clientJob.Threads, connections: clientJob.Connections, duration: clientJob.Duration, pipelineDepth: clientJob.PipelineDepth, path: path, method: clientJob.Method, headers: clientJob.Headers, dimension: dimension, value: value, runtimeStore: serverJob.UseRuntimeStore) , 5000)); }
private static string CloneAndRestore(string path, ServerJob job) { // It's possible that the user specified a custom branch/commit for the benchmarks repo, // so we need to add that to the set of sources to restore if it's not already there. // // Note that this is also going to de-dupe the repos if the same one was specified twice at // the command-line (last first to support overrides). var repos = new HashSet <Source>(job.Sources, SourceRepoComparer.Instance); // This will no-op if 'benchmarks' was specified by the user. repos.Add(_benchmarksSource); // Clone string benchmarksDir = null; var dirs = new List <string>(); foreach (var source in repos) { var dir = Git.Clone(path, source.Repository); if (SourceRepoComparer.Instance.Equals(source, _benchmarksSource)) { benchmarksDir = dir; } if (!string.IsNullOrEmpty(source.BranchOrCommit)) { Git.Checkout(Path.Combine(path, dir), source.BranchOrCommit); } dirs.Add(dir); } Debug.Assert(benchmarksDir != null); // Modify all global.json to reference source dirs foreach (var repoDir in dirs) { var globalJsonPath = Path.Combine(path, repoDir, "global.json"); dynamic globalJson = JsonConvert.DeserializeObject(File.ReadAllText(globalJsonPath)); foreach (var sourceDir in dirs) { if (sourceDir == benchmarksDir) { // No need to add benchmarks to global.json, since nothing should depend on it continue; } globalJson["projects"].Add(Path.Combine("..", sourceDir, "src")); } File.WriteAllText(globalJsonPath, JsonConvert.SerializeObject(globalJson, Formatting.Indented)); } // Restore in each dir foreach (var dir in dirs) { ProcessUtil.Run("dotnet", "restore", workingDirectory: Path.Combine(path, dir, "src")); } return(benchmarksDir); }
public JobResult(ServerJob job, IUrlHelper urlHelper) { Id = job.Id; RunId = job.RunId; State = job.State.ToString(); DetailsUrl = urlHelper.ActionLink("GetById", "Jobs", new { Id }); BuildLogsUrl = urlHelper.ActionLink("BuildLog", "Jobs", new { Id }); OutputLogsUrl = urlHelper.ActionLink("Output", "Jobs", new { Id }); }
public IActionResult Create([FromBody] ServerJob job) { if (job == null || job.Id != 0 || job.State != ServerState.Waiting || job.Sources.Any(source => string.IsNullOrEmpty(source.Repository))) { return(BadRequest()); } job = _jobs.Add(job); Response.Headers["Location"] = $"/jobs/{job.Id}"; return(new StatusCodeResult((int)HttpStatusCode.Accepted)); }
private static Process StartProcess(string hostname, string benchmarksRepo, ServerJob job) { var filename = "dotnet"; var arguments = $"run -c Release -- --scenarios {job.Scenario} --server.urls {job.Scheme.ToString().ToLowerInvariant()}://{hostname}:5000"; if (!string.IsNullOrEmpty(job.ConnectionFilter)) { arguments += $" --connectionFilter {job.ConnectionFilter}"; } Log.WriteLine($"Starting process '{filename} {arguments}'"); var process = new Process() { StartInfo = { FileName = filename, Arguments = arguments, WorkingDirectory = Path.Combine(benchmarksRepo, @"src\Benchmarks"), RedirectStandardOutput = true, UseShellExecute = false, }, EnableRaisingEvents = true }; process.StartInfo.Environment.Add("COREHOST_SERVER_GC", "1"); process.OutputDataReceived += (_, e) => { if (e != null && e.Data != null) { Log.WriteLine(e.Data); if (job.State == ServerState.Starting && e.Data.Contains("Application started")) { job.State = ServerState.Running; job.Url = ComputeServerUrl(hostname, job.Scheme, job.Scenario); Log.WriteLine($"Running job '{job.Id}' with scenario '{job.Scenario}'"); } } }; process.Start(); process.BeginOutputReadLine(); return(process); }
public async Task WriteJobResultsToSqlAsync( ServerJob serverJob, ClientJob clientJob, string sqlConnectionString, string tableName, string path, string session, string description, Statistics statistics, bool longRunning) { var utcNow = DateTime.UtcNow; var scenario = serverJob.Scenario; foreach (var result in CsvResults) { serverJob.Scenario = $"{scenario}.{result.Class}.{result.Method}{result.Params ?? ""}"; await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "OperationsPerSecond", value : result.OperationsPerSecond); await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Allocated (KB)", value : result.Allocated); } serverJob.Scenario = scenario; }
public IActionResult Create([FromBody] ServerJob job) { lock (_jobs) { if (job == null || job.Id != 0 || job.State != ServerState.Initializing) { return(BadRequest()); } job.Hardware = Startup.Hardware; job.HardwareVersion = Startup.HardwareVersion; job.OperatingSystem = Startup.OperatingSystem; job = _jobs.Add(job); Response.Headers["Location"] = $"/jobs/{job.Id}"; return(new StatusCodeResult((int)HttpStatusCode.Accepted)); } }
private static async Task <int> UploadFileAsync(string filename, ServerJob serverJob, string uri) { Log.Write($"Uploading {filename} to {uri}"); try { var outputFileSegments = filename.Split(';'); var uploadFilename = outputFileSegments[0]; if (!File.Exists(uploadFilename)) { Console.WriteLine($"File '{uploadFilename}' could not be loaded."); return(8); } var destinationFilename = outputFileSegments.Length > 1 ? outputFileSegments[1] : Path.GetFileName(uploadFilename); using (var request = new HttpRequestMessage(HttpMethod.Post, uri)) { var fileContent = uploadFilename.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? new StreamContent(await _httpClient.GetStreamAsync(uploadFilename)) : new StreamContent(new FileStream(uploadFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1, FileOptions.Asynchronous | FileOptions.SequentialScan)); using (fileContent) { request.Content = fileContent; request.Headers.Add("id", serverJob.Id.ToString()); request.Headers.Add("destinationFilename", destinationFilename); await _httpClient.SendAsync(request); } } } catch (Exception e) { throw new InvalidOperationException($"An error occurred while uploading a file.", e); } return(0); }
public IActionResult Create([FromBody] ServerJob job) { lock (_jobs) { if (job == null || job.Id != 0 || job.State != ServerState.Initializing) { return(BadRequest()); } job.Hardware = Startup.Hardware; job.HardwareVersion = Startup.HardwareVersion; job.OperatingSystem = Startup.OperatingSystem; // Use server-side date and time to prevent issues fron time drifting job.LastDriverCommunicationUtc = DateTime.UtcNow; job = _jobs.Add(job); Response.Headers["Location"] = $"/jobs/{job.Id}"; return(new StatusCodeResult((int)HttpStatusCode.Accepted)); } }
public async Task WriteJobResultsToSqlAsync( ServerJob serverJob, ClientJob clientJob, string sqlConnectionString, string tableName, string path, string session, string description, Statistics statistics, bool longRunning) { var utcNow = DateTime.UtcNow; await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "RequestsPerSecond", value : statistics.RequestsPerSecond); if (statistics.StartupMain != -1 && !longRunning) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Startup Main (ms)", value : statistics.StartupMain); } if (statistics.FirstRequest != -1 && !longRunning) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "First Request (ms)", value : statistics.FirstRequest); } await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "WorkingSet (MB)", value : statistics.WorkingSet); await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "CPU", value : statistics.Cpu); if (statistics.Latency != -1 && !longRunning) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, session : session, description : description, path : serverJob.Path, dimension : "Latency (ms)", value : statistics.Latency); } if (statistics.LatencyAverage != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "LatencyAverage (ms)", value : statistics.LatencyAverage); } if (statistics.Latency50Percentile != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Latency50Percentile (ms)", value : statistics.Latency50Percentile); } if (statistics.Latency75Percentile != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Latency75Percentile (ms)", value : statistics.Latency75Percentile); } if (statistics.Latency90Percentile != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Latency90Percentile (ms)", value : statistics.Latency90Percentile); } if (statistics.Latency99Percentile != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Latency99Percentile (ms)", value : statistics.Latency99Percentile); } if (statistics.MaxLatency != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "MaxLatency (ms)", value : statistics.MaxLatency); } if (statistics.SocketErrors != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "SocketErrors", value : statistics.SocketErrors); } if (statistics.BadResponses != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "BadResponses", value : statistics.BadResponses); } if (statistics.TotalRequests != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "TotalRequests", value : statistics.TotalRequests); } if (statistics.Duration != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Duration (ms)", value : statistics.Duration); } }
public async Task WriteJobResultsToSqlAsync( ServerJob serverJob, ClientJob clientJob, string sqlConnectionString, string tableName, string path, string session, string description, Statistics statistics, bool longRunning) { var utcNow = DateTime.UtcNow; await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "RequestsPerSecond", value : statistics.RequestsPerSecond); if (statistics.StartupMain != -1 && !longRunning) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Startup Main (ms)", value : statistics.StartupMain); } if (statistics.BuildTime != -1 && !longRunning) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Build Time (ms)", value : statistics.BuildTime); } if (statistics.PublishedSize != -1 && !longRunning) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Published Size (KB)", value : statistics.PublishedSize); } if (statistics.FirstRequest != -1 && !longRunning) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "First Request (ms)", value : statistics.FirstRequest); } await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "WorkingSet (MB)", value : statistics.WorkingSet); await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "CPU", value : statistics.Cpu); if (statistics.Latency != -1 && !longRunning) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, session : session, description : description, path : serverJob.Path, dimension : "Latency (ms)", value : statistics.Latency); } if (statistics.LatencyAverage != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "LatencyAverage (ms)", value : statistics.LatencyAverage); } if (statistics.Latency50Percentile != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Latency50Percentile (ms)", value : statistics.Latency50Percentile); } if (statistics.Latency75Percentile != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Latency75Percentile (ms)", value : statistics.Latency75Percentile); } if (statistics.Latency90Percentile != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Latency90Percentile (ms)", value : statistics.Latency90Percentile); } if (statistics.Latency99Percentile != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Latency99Percentile (ms)", value : statistics.Latency99Percentile); } if (statistics.MaxLatency != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "MaxLatency (ms)", value : statistics.MaxLatency); } if (statistics.SocketErrors != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "SocketErrors", value : statistics.SocketErrors); } if (statistics.BadResponses != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "BadResponses", value : statistics.BadResponses); } if (statistics.TotalRequests != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "TotalRequests", value : statistics.TotalRequests); } if (statistics.Duration != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : "Duration (ms)", value : statistics.Duration); } if (statistics.Other.Any()) { foreach (var counter in Program.Counters) { if (!statistics.Other.ContainsKey(counter.Name)) { continue; } if (statistics.Other[counter.Name] != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : sqlConnectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : counter.DisplayName, value : statistics.Other[counter.Name]); } } } }
private Task WriteJobsToSql(ServerJob serverJob, ClientJob clientJob, DateTime utcNow, string connectionString, string tableName, string path, string session, string description, string dimension, double value) { return(RetryOnExceptionAsync(5, (retry) => WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, dimension, value, retry))); }
public Task WriteJobResultsToSqlAsync(ServerJob serverJob, ClientJob clientJob, string connectionString, string tableName, string path, string session, string description, Statistics statistics, bool longRunning) { return(Task.CompletedTask); }
public async Task WriteJobResultsToSqlAsync(ServerJob serverJob, ClientJob clientJob, string connectionString, string tableName, string path, string session, string description, Statistics statistics, bool longRunning) { var utcNow = DateTime.UtcNow; await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "RequestsPerSecond", statistics.RequestsPerSecond); await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "CPU", statistics.Cpu); await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "WorkingSet (MB)", statistics.WorkingSet); if (statistics.LatencyAverage != -1) { await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "Latency Average (ms)", statistics.LatencyAverage); } if (statistics.Latency50Percentile != -1) { await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "Latency50Percentile (ms)", statistics.Latency50Percentile); } if (statistics.Latency75Percentile != -1) { await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "Latency75Percentile (ms)", statistics.Latency75Percentile); } if (statistics.Latency90Percentile != -1) { await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "Latency90Percentile (ms)", statistics.Latency90Percentile); } if (statistics.Latency99Percentile != -1) { await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "Latency99Percentile (ms)", statistics.Latency99Percentile); } if (statistics.MaxLatency != -1) { await WriteJobsToSql(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, "MaxLatency (ms)", statistics.MaxLatency); } if (statistics.Other.Any()) { foreach (var counter in Program.Counters) { if (!statistics.Other.ContainsKey(counter.Name)) { continue; } if (statistics.Other[counter.Name] != -1) { await WriteJobsToSql( serverJob : serverJob, clientJob : clientJob, utcNow : utcNow, connectionString : connectionString, tableName : tableName, path : serverJob.Path, session : session, description : description, dimension : counter.DisplayName, value : statistics.Other[counter.Name]); } } } }
public JobConnection(ServerJob definition, Uri serverUri) { Job = definition; _serverUri = serverUri; _serverJobsUri = new Uri(_serverUri, "/jobs"); }
public async Task <string> StartAsync( string jobName, CommandOption _outputArchiveOption, CommandOption _buildArchiveOption ) { _jobName = jobName; var content = JsonConvert.SerializeObject(Job); Log.Write($"Starting job '{_jobName}' ..."); Log.Verbose($"POST {_serverJobsUri} {content} ..."); var response = await _httpClient.PostAsync(_serverJobsUri, new StringContent(content, Encoding.UTF8, "application/json")); var responseContent = await response.Content.ReadAsStringAsync(); Log.Verbose($"{(int)response.StatusCode} {response.StatusCode}"); response.EnsureSuccessStatusCode(); _serverJobUri = new Uri(_serverUri, response.Headers.Location).ToString(); Log.Write($"Fetching job: {_serverJobUri}"); // When a job is submitted it has the state New // Waiting for the job to be selected (Initializing), then upload custom files and send the start while (true) { Log.Verbose($"GET {_serverJobUri} ..."); response = await _httpClient.GetAsync(_serverJobUri); responseContent = await response.Content.ReadAsStringAsync(); response.EnsureSuccessStatusCode(); Job = JsonConvert.DeserializeObject <ServerJob>(responseContent); #region Ensure the job is valid if (Job.ServerVersion < 3) { throw new Exception($"Invalid server version ({Job.ServerVersion}), please update your server to match this driver version."); } if (!Job.Hardware.HasValue) { throw new InvalidOperationException("Server is required to set ServerJob.Hardware."); } if (String.IsNullOrWhiteSpace(Job.HardwareVersion)) { throw new InvalidOperationException("Server is required to set ServerJob.HardwareVersion."); } if (!Job.OperatingSystem.HasValue) { throw new InvalidOperationException("Server is required to set ServerJob.OperatingSystem."); } #endregion if (Job.State == ServerState.Initializing) { Log.Write($"Job has been selected by the server ..."); StartKeepAlive(); // Uploading source code if (!String.IsNullOrEmpty(Job.Source.LocalFolder)) { // Zipping the folder var tempFilename = Path.GetTempFileName(); File.Delete(tempFilename); Log.Write("Zipping the source folder in " + tempFilename); var sourceDir = Job.Source.LocalFolder; if (!File.Exists(Path.Combine(sourceDir, ".gitignore"))) { ZipFile.CreateFromDirectory(sourceDir, tempFilename); } else { Log.Verbose(".gitignore file found"); DoCreateFromDirectory(sourceDir, tempFilename); } var result = await UploadFileAsync(tempFilename, Job, _serverJobUri + "/source"); File.Delete(tempFilename); if (result != 0) { throw new Exception("Error while uploading source files"); } } // Upload custom package contents if (_outputArchiveOption.HasValue()) { foreach (var outputArchiveValue in _outputArchiveOption.Values) { var outputFileSegments = outputArchiveValue.Split(';', 2, StringSplitOptions.RemoveEmptyEntries); string localArchiveFilename = outputFileSegments[0]; var tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); if (Directory.Exists(tempFolder)) { Directory.Delete(tempFolder, true); } Directory.CreateDirectory(tempFolder); _temporaryFolders.Add(tempFolder); // Download the archive, while pinging the server to keep the job alive if (outputArchiveValue.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { localArchiveFilename = await DownloadTemporaryFileAsync(localArchiveFilename, _serverJobUri); } ZipFile.ExtractToDirectory(localArchiveFilename, tempFolder); if (outputFileSegments.Length > 1) { Job.Options.OutputFiles.Add(Path.Combine(tempFolder, "*.*") + ";" + outputFileSegments[1]); } else { Job.Options.OutputFiles.Add(Path.Combine(tempFolder, "*.*")); } } } // Upload custom build package contents if (_buildArchiveOption.HasValue()) { foreach (var buildArchiveValue in _buildArchiveOption.Values) { var buildFileSegments = buildArchiveValue.Split(';', 2, StringSplitOptions.RemoveEmptyEntries); string localArchiveFilename = buildFileSegments[0]; var tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); if (Directory.Exists(tempFolder)) { Directory.Delete(tempFolder, true); } Directory.CreateDirectory(tempFolder); _temporaryFolders.Add(tempFolder); // Download the archive, while pinging the server to keep the job alive if (buildArchiveValue.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { localArchiveFilename = await DownloadTemporaryFileAsync(localArchiveFilename, _serverJobUri); } ZipFile.ExtractToDirectory(localArchiveFilename, tempFolder); if (buildFileSegments.Length > 1) { Job.Options.BuildFiles.Add(Path.Combine(tempFolder, "*.*") + ";" + buildFileSegments[1]); } else { Job.Options.BuildFiles.Add(Path.Combine(tempFolder, "*.*")); } } } // Uploading build files if (Job.Options.BuildFiles.Any()) { foreach (var buildFileValue in Job.Options.BuildFiles) { var buildFileSegments = buildFileValue.Split(';', 2, StringSplitOptions.RemoveEmptyEntries); var shouldSearchRecursively = buildFileSegments[0].Contains("*.*"); foreach (var resolvedFile in Directory.GetFiles(Path.GetDirectoryName(buildFileSegments[0]), Path.GetFileName(buildFileSegments[0]), shouldSearchRecursively ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)) { var resolvedFileWithDestination = resolvedFile; if (buildFileSegments.Length > 1) { resolvedFileWithDestination += ";" + buildFileSegments[1] + Path.GetDirectoryName(resolvedFile).Substring(Path.GetDirectoryName(buildFileSegments[0]).Length) + "/" + Path.GetFileName(resolvedFileWithDestination); } var result = await UploadFileAsync(resolvedFileWithDestination, Job, _serverJobUri + "/build"); if (result != 0) { throw new Exception("Error while uploading build files"); } } } } // Uploading attachments if (Job.Options.OutputFiles.Any()) { foreach (var outputFileValue in Job.Options.OutputFiles) { var outputFileSegments = outputFileValue.Split(';', 2, StringSplitOptions.RemoveEmptyEntries); var shouldSearchRecursively = outputFileSegments[0].Contains("*.*"); foreach (var resolvedFile in Directory.GetFiles(Path.GetDirectoryName(outputFileSegments[0]), Path.GetFileName(outputFileSegments[0]), shouldSearchRecursively ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)) { var resolvedFileWithDestination = resolvedFile; if (outputFileSegments.Length > 1) { resolvedFileWithDestination += ";" + outputFileSegments[1] + Path.GetDirectoryName(resolvedFile).Substring(Path.GetDirectoryName(outputFileSegments[0]).Length) + "/" + Path.GetFileName(resolvedFileWithDestination); } var result = await UploadFileAsync(resolvedFileWithDestination, Job, _serverJobUri + "/attachment"); if (result != 0) { throw new Exception("Error while uploading output files"); } } } } response = await _httpClient.PostAsync(_serverJobUri + "/start", new StringContent("")); responseContent = await response.Content.ReadAsStringAsync(); Log.Verbose($"{(int)response.StatusCode} {response.StatusCode}"); response.EnsureSuccessStatusCode(); Job = JsonConvert.DeserializeObject <ServerJob>(responseContent); Log.Write($"Job is now building ..."); break; } else { await Task.Delay(1000); } } // Tracking the job until it stops // TODO: Add a step on the server before build and start, such that start can be as fast as possible // "start" => "build" // + new start call while (true) { var previousJob = Job; Log.Verbose($"GET {_serverJobUri} ..."); response = await _httpClient.GetAsync(_serverJobUri); responseContent = await response.Content.ReadAsStringAsync(); Log.Verbose($"{(int)response.StatusCode} {response.StatusCode} {responseContent}"); if (response.StatusCode == HttpStatusCode.NotFound) { throw new Exception("Job not found"); } Job = JsonConvert.DeserializeObject <ServerJob>(responseContent); if (Job.State == ServerState.Running) { if (previousJob.State != ServerState.Running) { Log.Write($"Job is running"); _runningUtc = DateTime.UtcNow; } return(Job.Url); } else if (Job.State == ServerState.Failed) { Log.Write($"Job failed on benchmark server, stopping ..."); Log.Write(Job.Error, notime: true, error: true); // Returning will also send a Delete message to the server return(null); } else if (Job.State == ServerState.NotSupported) { Log.Write("Server does not support this job configuration."); return(null); } else if (Job.State == ServerState.Stopped) { Log.Write($"Job finished"); // If there is no ReadyStateText defined, the server will never be in Running state // and we'll reach the Stopped state eventually, but that's a normal behavior. if (Job.WaitForExit) { return(Job.Url); } throw new Exception("Job finished unnexpectedly"); } else { await Task.Delay(1000); } } }
internal override bool Query() { using (SQLConnection sql = new SQLConnection(instance)) { sql.BuildConnectionString(credentials); if (!sql.Connect()) { return(false); } if (!_Check(sql)) { return(false); } StringBuilder sb = new StringBuilder(); sb.Append(QUERY2_1); if (!string.IsNullOrEmpty(keywordFilter)) { sb.Append(keywordFilter); } if (!string.IsNullOrEmpty(subsystemFilter)) { sb.Append(subsystemFilter); } if (!string.IsNullOrEmpty(proxyCredFilter)) { sb.Append(proxyCredFilter); } if (!string.IsNullOrEmpty(usingProxyCredFilter)) { sb.Append(usingProxyCredFilter); } table = sql.Query(sb.ToString()); } foreach (DataRow row in table.AsEnumerable()) { try { ServerJob sj = new ServerJob { ComputerName = computerName, Instance = instance, DatabaseName = database, Job_Id = (int)row["Job_Id"], Job_Name = (string)row["Job_Name"], Job_Description = (string)row["Job_Description"], Job_Owner = (string)row["Job_Owner"], Proxy_Id = (int)row["Proxy_Id"], Proxy_Credential = (string)row["Proxy_Credential"], Date_Created = (string)row["Date_Created"], Last_Run_Date = (DateTime)row["Last_Run_Date"], Enabled = (bool)row["Enabled"], Server = (string)row["Server"], Step_Name = (string)row["Step_Name"], SubSystem = (string)row["SubSystem"], Command = (string)row["Command"] }; #if DEBUG Misc.PrintStruct <ServerJob>(sj); #endif serverJobs.Add(sj); } catch (Exception ex) { if (ex is ArgumentNullException) { Console.WriteLine("Empty Response"); } else { Console.WriteLine(ex.Message); } return(false); } } return(true); }
private async Task WriteJobResultToSqlAsync(ServerJob serverJob, ClientJob clientJob, DateTime utcNow, string connectionString, string tableName, string path, string session, string description, Statistics statistics, bool longRunning, string dimension, double value, bool checkExisting) { if (checkExisting) { if (await CheckForRow(connectionString, tableName, utcNow, dimension, session) == true) { return; } } string insertCmd = @" INSERT INTO [dbo].[" + tableName + @"] ([DateTime] ,[Session] ,[Description] ,[AspNetCoreVersion] ,[RuntimeVersion] ,[Scenario] ,[Hardware] ,[HardwareVersion] ,[OperatingSystem] ,[Framework] ,[RuntimeStore] ,[Scheme] ,[Sources] ,[WebHost] ,[Transport] ,[HubProtocol] ,[ClientProperties] ,[Connections] ,[Duration] ,[Path] ,[Headers] ,[Dimension] ,[Value]) VALUES (@DateTime ,@Session ,@Description ,@AspNetCoreVersion ,@RuntimeVersion ,@Scenario ,@Hardware ,@HardwareVersion ,@OperatingSystem ,@Framework ,@RuntimeStore ,@Scheme ,@Sources ,@WebHost ,@Transport ,@HubProtocol ,@ClientProperties ,@Connections ,@Duration ,@Path ,@Headers ,@Dimension ,@Value) "; using (var connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); var transaction = connection.BeginTransaction(); try { var command = new SqlCommand(insertCmd, connection, transaction); var p = command.Parameters; p.AddWithValue("@DateTime", utcNow); p.AddWithValue("@Session", session); p.AddWithValue("@Description", description); p.AddWithValue("@AspNetCoreVersion", serverJob.AspNetCoreVersion); p.AddWithValue("@RuntimeVersion", serverJob.RuntimeVersion); p.AddWithValue("@Scenario", serverJob.Scenario.ToString()); p.AddWithValue("@Hardware", serverJob.Hardware.ToString()); p.AddWithValue("@HardwareVersion", serverJob.HardwareVersion); p.AddWithValue("@OperatingSystem", serverJob.OperatingSystem.ToString()); p.AddWithValue("@Framework", "Core"); p.AddWithValue("@RuntimeStore", serverJob.UseRuntimeStore); p.AddWithValue("@Scheme", serverJob.Scheme.ToString().ToLowerInvariant()); p.AddWithValue("@Sources", serverJob.Source != null ? ConvertToSqlString(serverJob.Source) : (object)DBNull.Value); p.AddWithValue("@WebHost", serverJob.WebHost.ToString()); p.AddWithValue("@Transport", clientJob.ClientProperties["TransportType"]); p.AddWithValue("@HubProtocol", clientJob.ClientProperties["HubProtocol"]); p.AddWithValue("@ClientProperties", JsonConvert.SerializeObject(clientJob.ClientProperties)); p.AddWithValue("@Connections", clientJob.Connections); p.AddWithValue("@Duration", clientJob.Duration); p.AddWithValue("@Path", string.IsNullOrEmpty(path) ? (object)DBNull.Value : path); p.AddWithValue("@Headers", clientJob.Headers.Any() ? JsonConvert.SerializeObject(clientJob.Headers) : (object)DBNull.Value); p.AddWithValue("@Dimension", dimension); p.AddWithValue("@Value", value); await command.ExecuteNonQueryAsync(); transaction.Commit(); } catch { transaction.Rollback(); throw; } finally { transaction.Dispose(); } } }
public static int Main(string[] args) { var app = new CommandLineApplication() { Name = "BenchmarksDriver", FullName = "ASP.NET Benchmark Driver", Description = "Driver for ASP.NET Benchmarks" }; app.HelpOption("-?|-h|--help"); // Driver Options var serverOption = app.Option("-s|--server", "URL of benchmark server", CommandOptionType.SingleValue); var clientOption = app.Option("-c|--client", "URL of benchmark client", CommandOptionType.SingleValue); var sqlConnectionStringOption = app.Option("-q|--sql", "Connection string of SQL Database to store results", CommandOptionType.SingleValue); // ServerJob Options var connectionFilterOption = app.Option("-f|--connectionFilter", "Assembly-qualified name of the ConnectionFilter", CommandOptionType.SingleValue); var scenarioOption = app.Option("-n|--scenario", "Benchmark scenario to run", CommandOptionType.SingleValue); var schemeOption = app.Option("-m|--scheme", "Scheme (http or https). Default is http.", CommandOptionType.SingleValue); var sourceOption = app.Option("-o|--source", "Source dependency. Format is 'repo@branchOrCommit'. " + "Repo can be a full URL, or a short name under https://github.com/aspnet.", CommandOptionType.MultipleValue); // ClientJob Options var connectionsOption = app.Option("--connections", "Number of connections used by client", CommandOptionType.SingleValue); var durationOption = app.Option("--duration", "Duration of test in seconds", CommandOptionType.SingleValue); var pipelineDepthOption = app.Option("--pipelineDepth", "Depth of pipeline used by client", CommandOptionType.SingleValue); var threadsOption = app.Option("--threads", "Number of threads used by client", CommandOptionType.SingleValue); var headerOption = app.Option("--header", "Header added to request", CommandOptionType.MultipleValue); app.OnExecute(() => { var schemeValue = schemeOption.Value(); if (string.IsNullOrEmpty(schemeValue)) { schemeValue = "http"; } var server = serverOption.Value(); var client = clientOption.Value(); var sqlConnectionString = sqlConnectionStringOption.Value(); Scheme scheme; Scenario scenario; if (!Enum.TryParse(schemeValue, ignoreCase: true, result: out scheme) || !Enum.TryParse(scenarioOption.Value(), ignoreCase: true, result: out scenario) || string.IsNullOrWhiteSpace(server) || string.IsNullOrWhiteSpace(client)) { app.ShowHelp(); return(2); } var serverJob = new ServerJob() { Scheme = scheme, Scenario = scenario, }; if (connectionFilterOption.HasValue()) { serverJob.ConnectionFilter = connectionFilterOption.Value(); } var sources = new List <Source>(); foreach (var source in sourceOption.Values) { var split = source.IndexOf('@'); var repository = (split == -1) ? source : source.Substring(0, split); var branch = (split == -1) ? null : source.Substring(split + 1); if (!repository.Contains(":")) { repository = $"https://github.com/aspnet/{repository}.git"; } sources.Add(new Source() { BranchOrCommit = branch, Repository = repository }); } serverJob.Sources = sources; // Override default ClientJob settings if options are set if (connectionsOption.HasValue()) { _clientJobs.Values.ToList().ForEach(c => c.Connections = int.Parse(connectionsOption.Value())); } if (threadsOption.HasValue()) { _clientJobs.Values.ToList().ForEach(c => c.Threads = int.Parse(threadsOption.Value())); } if (durationOption.HasValue()) { _clientJobs.Values.ToList().ForEach(c => c.Duration = int.Parse(durationOption.Value())); } if (pipelineDepthOption.HasValue()) { _clientJobs.Values.ToList().ForEach(c => c.PipelineDepth = int.Parse(pipelineDepthOption.Value())); } if (headerOption.HasValue()) { _clientJobs.Values.ToList().ForEach(c => c.Headers = headerOption.Values.ToArray()); } return(Run(new Uri(server), new Uri(client), sqlConnectionString, serverJob).Result); }); return(app.Execute(args)); }
private static async Task <int> Run(Uri serverUri, Uri clientUri, string sqlConnectionString, ServerJob serverJob) { var scenario = serverJob.Scenario; var serverJobsUri = new Uri(serverUri, "/jobs"); Uri serverJobUri = null; HttpResponseMessage response = null; string responseContent = null; try { Log($"Starting scenario {scenario} on benchmark server..."); var content = JsonConvert.SerializeObject(serverJob); LogVerbose($"POST {serverJobsUri} {content}..."); response = await _httpClient.PostAsync(serverJobsUri, new StringContent(content, Encoding.UTF8, "application/json")); responseContent = await response.Content.ReadAsStringAsync(); LogVerbose($"{(int)response.StatusCode} {response.StatusCode}"); response.EnsureSuccessStatusCode(); serverJobUri = new Uri(serverUri, response.Headers.Location); var serverBenchmarkUri = (string)null; while (true) { LogVerbose($"GET {serverJobUri}..."); response = await _httpClient.GetAsync(serverJobUri); responseContent = await response.Content.ReadAsStringAsync(); LogVerbose($"{(int)response.StatusCode} {response.StatusCode} {responseContent}"); serverJob = JsonConvert.DeserializeObject <ServerJob>(responseContent); if (serverJob.State == ServerState.Running) { serverBenchmarkUri = serverJob.Url; break; } else if (serverJob.State == ServerState.Failed) { throw new InvalidOperationException("Server job failed"); } else { await Task.Delay(1000); } } Log("Warmup"); await RunClientJob(scenario, clientUri, serverBenchmarkUri); Log("Benchmark"); var clientJob = await RunClientJob(scenario, clientUri, serverBenchmarkUri); if (clientJob.State == ClientState.Completed && !string.IsNullOrWhiteSpace(sqlConnectionString)) { await WriteResultsToSql(sqlConnectionString, scenario, serverJob.Scheme, serverJob.ConnectionFilter, clientJob.Threads, clientJob.Connections, clientJob.Duration, clientJob.PipelineDepth, clientJob.Headers, clientJob.RequestsPerSecond); } } finally { if (serverJobUri != null) { Log($"Stopping scenario {scenario} on benchmark server..."); LogVerbose($"DELETE {serverJobUri}..."); response = _httpClient.DeleteAsync(serverJobUri).Result; LogVerbose($"{(int)response.StatusCode} {response.StatusCode}"); response.EnsureSuccessStatusCode(); } } return(0); }
public async Task WriteJobResultsToSqlAsync(ServerJob serverJob, ClientJob clientJob, string connectionString, string tableName, string path, string session, string description, Statistics statistics, bool longRunning) { var utcNow = DateTime.UtcNow; await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "RequestsPerSecond", statistics.RequestsPerSecond, retry); }); await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "CPU", statistics.Cpu, retry); }); await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "WorkingSet (MB)", statistics.WorkingSet, retry); }); if (statistics.LatencyAverage != -1) { await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "Latency Average (ms)", statistics.LatencyAverage, retry); }); } if (statistics.Latency50Percentile != -1) { await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "Latency50Percentile (ms)", statistics.Latency50Percentile, retry); }); } if (statistics.Latency75Percentile != -1) { await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "Latency75Percentile (ms)", statistics.Latency75Percentile, retry); }); } if (statistics.Latency90Percentile != -1) { await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "Latency90Percentile (ms)", statistics.Latency90Percentile, retry); }); } if (statistics.Latency99Percentile != -1) { await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "Latency99Percentile (ms)", statistics.Latency99Percentile, retry); }); } if (statistics.MaxLatency != -1) { await RetryOnExceptionAsync(5, async (retry) => { await WriteJobResultToSqlAsync(serverJob, clientJob, utcNow, connectionString, tableName, path, session, description, statistics, longRunning, "MaxLatency (ms)", statistics.MaxLatency, retry); }); } }