Nell’ultimo periodo ho avuto il privilegio di dedicare un po’ del mio tempo lavorativo a performance testing, in particolare load testing. (privilegio perchè quando “bombardi” per la prima volta il tuo “amato” sistema con un decente numero di utenti e vedi l’event log macchiarsi di rosso…1 o 2 cosucce interessanti le impari)

Comunque, risolti i problemini di cui sopra, si passa all’analisi dei risultati e quelli alla fine piu’ richiesti sono i dati percentile. VS fornisce out-of-the-box solo 95th e 90th percentile – da http://vstt2008qrg.codeplex.com/:

How 90% and 95% response times are calculated
Within the load test results summary page, the percentile values mean that:

  • 90% of the total transactions were completed in less than <time> seconds
  • 95% of the total transactions were completed in less than <time> seconds

Ma come ricavare altri valori percentile (85, 80, …)? Per ora ho trovato 2 metodi:

  1. usare le stored procedure del db LoadTest (vedi sotto)
  2. (sconsigliato) esportare i risultati del test run da VS a Excel e usare la funzione “PERCENTILE” di Excel. I valori che risultano da questo approccio non sono accurati però, siccome solo “the sample data” viene esportata su excel, cioè i dati che vengono salvati ad ogni intervallo di sampling (default: 5 sec). 

Premetto che non ho provato MS VSTS Load Test Reporting Sample (non mi serve al momento) e quello che cerco potrebbe essere già implementato li.

Requisiti:

Per calcolare dati percentile e’ necessario salvare tutti i risultati del test run su db (help):

image_thumb

Metodo accurato:

Si tratta di riutilizzare un po’ delle stored procedures del database LoadTest (dove i risultati vengono salvati). Prima di tutto bisogna individuare l’id del test run che si vuole analizzare

   1: USE [LoadTest]
   2: EXECUTE [dbo].[Prc_GetCompletedLoadTestRuns]

 

Una volta trovato l’id, lo si sostituisce nello script seguente alla riga  14:

   1: DECLARE @LoadTestRunId int
   2: DECLARE @TestCaseId int
   3: DECLARE    @ScenarioName nvarchar(64)
   4: DECLARE    @TestCaseName nvarchar(64)
   5: DECLARE    @Percentile95 float
   6: DECLARE    @Percentile90 float
   7: DECLARE    @Percentile85 float
   8: DECLARE    @Percentile80 float
   9: DECLARE    @Percentile75 float
  10: DECLARE    @Percentile70 float
  11: DECLARE    @Percentile65 float
  12: DECLARE    @Percentile60 float
  13:  
  14: SET @LoadTestRunId=13 – (*) value retrieved with 'EXECUTE [dbo].[Prc_GetCompletedLoadTestRuns]'
  15:  
  16: DECLARE @TestCasesTable table (
  17:     TestCaseId int not null,
  18:     ScenarioName nvarchar(64),
  19:     TestCaseName nvarchar(64))
  20:  
  21: DECLARE @PercentileValues table (
  22:     TestCaseId int not null,
  23:     ScenarioName nvarchar(64),
  24:     TestCaseName nvarchar(64),
  25:     Percentile95 float,
  26:     Percentile90 float,
  27:     Percentile85 float,
  28:     Percentile80 float,
  29:     Percentile75 float,
  30:     Percentile70 float,
  31:     Percentile65 float,
  32:     Percentile60 float)
  33:  
  34: INSERT INTO @TestCasesTable
  35: EXECUTE [dbo].[Prc_GetTestCases] @LoadTestRunId
  36:  
  37: DECLARE mycursor CURSOR
  38: FOR (SELECT * FROM @TestCasesTable)
  39: OPEN mycursor
  40:  
  41: FETCH NEXT FROM mycursor
  42: INTO @TestCaseId, @ScenarioName, @TestCaseName
  43:  
  44: WHILE @@FETCH_STATUS = 0
  45: BEGIN
  46:  
  47:     -- 95th
  48:     SET @Percentile95 = (select min(ElapsedTime) from 
  49:     (select top 5 percent ElapsedTime from LoadTestTestDetail 
  50:         where LoadTestRunId = @LoadTestRunId and TestCaseId=@TestCaseId
  51:         order by ElapsedTime desc) as TopElapsedTimes)
  52:     -- 90th
  53:     SET @Percentile90 = (select min(ElapsedTime) from 
  54:     (select top 10 percent ElapsedTime from LoadTestTestDetail 
  55:         where LoadTestRunId = @LoadTestRunId and TestCaseId=@TestCaseId
  56:         order by ElapsedTime desc) as TopElapsedTimes)
  57:     -- 85th
  58:     SET @Percentile85 = (select min(ElapsedTime) from 
  59:     (select top 15 percent ElapsedTime from LoadTestTestDetail 
  60:         where LoadTestRunId = @LoadTestRunId and TestCaseId=@TestCaseId
  61:         order by ElapsedTime desc) as TopElapsedTimes)
  62:     -- 80th
  63:     SET @Percentile80 = (select min(ElapsedTime) from 
  64:     (select top 20 percent ElapsedTime from LoadTestTestDetail 
  65:         where LoadTestRunId = @LoadTestRunId and TestCaseId=@TestCaseId
  66:         order by ElapsedTime desc) as TopElapsedTimes)
  67:     -- 75th
  68:     SET @Percentile75 = (select min(ElapsedTime) from 
  69:     (select top 25 percent ElapsedTime from LoadTestTestDetail 
  70:         where LoadTestRunId = @LoadTestRunId and TestCaseId=@TestCaseId
  71:         order by ElapsedTime desc) as TopElapsedTimes)
  72:     -- 70th
  73:     SET @Percentile70 = (select min(ElapsedTime) from 
  74:     (select top 30 percent ElapsedTime from LoadTestTestDetail 
  75:         where LoadTestRunId = @LoadTestRunId and TestCaseId=@TestCaseId
  76:         order by ElapsedTime desc) as TopElapsedTimes)
  77:     -- 65th
  78:     SET @Percentile65 = (select min(ElapsedTime) from 
  79:     (select top 35 percent ElapsedTime from LoadTestTestDetail 
  80:         where LoadTestRunId = @LoadTestRunId and TestCaseId=@TestCaseId
  81:         order by ElapsedTime desc) as TopElapsedTimes)
  82:     -- 60th
  83:     SET @Percentile60 = (select min(ElapsedTime) from 
  84:     (select top 40 percent ElapsedTime from LoadTestTestDetail 
  85:         where LoadTestRunId = @LoadTestRunId and TestCaseId=@TestCaseId
  86:         order by ElapsedTime desc) as TopElapsedTimes)
  87:  
  88:     INSERT INTO @PercentileValues (TestCaseId, ScenarioName, TestCaseName, 
  89:             Percentile95, Percentile90, Percentile85, Percentile80, 
  90:             Percentile75, Percentile70, Percentile65, Percentile60)
  91:     VALUES (@TestCaseId, @ScenarioName, @TestCaseName,
  92:             @Percentile95, @Percentile90, @Percentile85, @Percentile80, 
  93:             @Percentile75, @Percentile70, @Percentile65, @Percentile60) 
  94:  
  95:     FETCH NEXT FROM mycursor
  96:     INTO @TestCaseId, @ScenarioName, @TestCaseName
  97:  
  98: END
  99: CLOSE mycursor
 100: DEALLOCATE mycursor
 101:  
 102: SELECT * FROM @PercentileValues

 

Fatto! L’ultimo stmt mostra i vari dati percentile per ogni testcase eseguito nel test run:

LoadTestResults_thumb6

Questo metodo è accurato perchè il calcolo viene eseguito usando tutti i dati presenti nel database per quel test run.