1 //Copyright (c) 2010-2011 Glyn Astill <glyn@8kb.co.uk>
\r
2 //Copyright Notice: GPL
\r
5 using System.Collections.Generic;
\r
9 using System.Threading;
\r
12 using System.Configuration;
\r
13 using System.Diagnostics;
\r
19 public static string sServerDescription = (string)ConfigurationManager.AppSettings["ServerDescription"];
\r
20 public static int iClients = Convert.ToInt32(ConfigurationManager.AppSettings["Clients"]);
\r
21 public static int iClientsScale = Convert.ToInt32(ConfigurationManager.AppSettings["ClientsScale"]);
\r
22 public static int iClientsMax = Convert.ToInt32(ConfigurationManager.AppSettings["ClientsMax"]);
\r
23 public static int iIterations = Convert.ToInt32(ConfigurationManager.AppSettings["Iterations"]);
\r
24 public static string sLogFile = (string)ConfigurationManager.AppSettings["LogFile"];
\r
25 public static string sCsvLogFile = (string)ConfigurationManager.AppSettings["CsvLogFile"];
\r
26 public static int iLogLevel = Convert.ToInt32(ConfigurationManager.AppSettings["LogLevel"]);
\r
27 public static bool bVerboseScreen = Convert.ToBoolean(ConfigurationManager.AppSettings["VerboseScreen"]);
\r
28 public static bool bOnFailureRetry = Convert.ToBoolean(ConfigurationManager.AppSettings["ConnectionRetry"]);
\r
29 public static bool bConnPerIteration = Convert.ToBoolean(ConfigurationManager.AppSettings["ConnectionPerIteration"]);
\r
30 public static string sConn = (string)ConfigurationManager.AppSettings["PgConnectionString"];
\r
31 public static string sTransactionsFile = (string)ConfigurationManager.AppSettings["TransactionsFile"];
\r
32 public static int iSleepTime = Convert.ToInt32(ConfigurationManager.AppSettings["SleepTime"]);
\r
34 public static Object oTransCounterLock = new Object();
\r
35 public static Object oIterationCounterLock = new Object();
\r
36 public static Object oTransDurationLock = new Object();
\r
37 public static Object oLogLock = new Object();
\r
39 //public static DataSet dsTransactions = readTransactionsFile(sTransactionsFile);
\r
40 public static XmlDocument xmlTransactions = readTransactionsFile(sTransactionsFile);
\r
43 private static PerformanceCounter oCpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
\r
44 private static PerformanceCounter oSysCpuCounter = new PerformanceCounter("Processor", "% Privileged Time", "_Total");
\r
45 private static PerformanceCounter oUseCpuCounter = new PerformanceCounter("Processor", "% User Time", "_Total");
\r
47 public static string timeStamp = "dd/MM/yyyy HH:mm";
\r
48 public static string[] aLogArray = new string[10000000];
\r
49 //public static double[] aTransactionTimeArray = new double[iClientsMax * iIterations * dsTransactions.Tables[0].Columns.Count];
\r
50 public static double[] aTransactionTimeArray = new double[iClientsMax * iIterations * xmlTransactions.SelectNodes("//transaction").Count];
\r
52 public static int iLogIndex, iRunningAtMax, iRunningAtMin, iMaxRunning, iCompletedIterations, iCompletedTransactions;
\r
53 public static int iCompletedQueries, iRunningClients, iRunningTransactions, iConnectionTimeouts;
\r
54 public static int iConnectionCeilingHit, iConnectionFailure, iConnectionRetries, iFailure, iTransactionTimeIndex;
\r
55 public static double iMaxTransDuration, iMinTransDuration;
\r
56 public static bool bRunning = false;
\r
58 static void Main(string[] args)
\r
62 MainWorker(iClients);
\r
64 else if (iClientsScale != 0)
\r
66 if (iClientsMax == 0)
\r
68 iClientsMax = iClientsScale;
\r
70 for (int i = iClientsScale; i <= iClientsMax; i= i+iClientsScale)
\r
77 public static void MainWorker(int iClientsRun)
\r
79 iClients = iClientsRun;
\r
81 Array.Clear(aLogArray, 0, iLogIndex);
\r
83 Array.Clear(aTransactionTimeArray, 0, iTransactionTimeIndex);
\r
84 iTransactionTimeIndex = 0;
\r
85 iMaxTransDuration = 0;
\r
86 iMinTransDuration = 100000000000000000;
\r
90 iCompletedIterations = 0;
\r
91 iCompletedTransactions = 0;
\r
92 iCompletedQueries = 0;
\r
93 iRunningClients = 0;
\r
94 iRunningTransactions = 0;
\r
95 iConnectionTimeouts = 0;
\r
96 iConnectionCeilingHit = 0;
\r
97 iConnectionFailure = 0;
\r
98 iConnectionRetries = 0;
\r
104 Info("-------------------- Test Start --------------------", iLogLevel, false);
\r
105 Info("Server Description: " + sServerDescription, iLogLevel, false);
\r
106 Info("Database load tester.", iLogLevel, true);
\r
107 Info("Iterations per client = " + iIterations, iLogLevel, true);
\r
108 Info("launching " + iClients + " clients...", iLogLevel, true);
\r
110 Thread[] workerThreads = new Thread[iClients];
\r
113 Thread infoThread = new Thread(new ThreadStart(InfoScreen));
\r
114 infoThread.Start();
\r
116 for (int i = 0; i < workerThreads.Length; i++)
\r
118 workerThreads[i] = new Thread(new ParameterizedThreadStart(ClientWorker));
\r
119 workerThreads[i].Start(i);
\r
123 for (int i = 0; i < workerThreads.Length; i++)
\r
125 workerThreads[i].Join();
\r
132 Info("-------------------- Test Complete --------------------", iLogLevel, false);
\r
136 public static void InfoScreen()
\r
138 DateTime startTime = DateTime.Now;
\r
139 DateTime currTime = DateTime.Now;
\r
140 TimeSpan duration = currTime - startTime;
\r
142 double iMeanTransactionDuration = 0;
\r
143 double iStandatdDeviation = 0;
\r
150 if (!bVerboseScreen)
\r
154 fCpuAll = fCpuAll + oCpuCounter.NextValue();
\r
155 fCpuSys = fCpuSys + oSysCpuCounter.NextValue();
\r
156 fCpuUse = fCpuUse + oUseCpuCounter.NextValue();
\r
159 currTime = DateTime.Now;
\r
160 duration = currTime - startTime;
\r
162 Console.SetCursorPosition(0, 4);
\r
163 Console.WriteLine("Running Clients {0} ", iRunningClients);
\r
164 Console.SetCursorPosition(0, 5);
\r
165 Console.WriteLine("Running Transactions {0} : {1} max ", iRunningTransactions, iMaxRunning);
\r
167 Console.SetCursorPosition(0, 7);
\r
168 Console.WriteLine("Completed Queries {0} : {1} qps ", iCompletedQueries, (iCompletedQueries / (Convert.ToInt32(duration.TotalSeconds) + 1)));
\r
169 Console.SetCursorPosition(0, 8);
\r
170 Console.WriteLine("Completed Transactions {0} : {1} tps ", iCompletedTransactions, (iCompletedTransactions / (Convert.ToInt32(duration.TotalSeconds) + 1)));
\r
171 Console.SetCursorPosition(0, 9);
\r
172 Console.WriteLine("Completed Iterations {0} / {1} ", iCompletedIterations, (iIterations * iClients));
\r
174 Console.SetCursorPosition(0, 11);
\r
175 Console.WriteLine("Maximum Transaction+Read Time {0} ms : {1} Running ", iMaxTransDuration, iRunningAtMax);
\r
176 Console.SetCursorPosition(0, 12);
\r
177 Console.WriteLine("Minimum Transaction+Read Time {0} ms : {1} Running ", iMinTransDuration, iRunningAtMin);
\r
179 Console.SetCursorPosition(0, 14);
\r
180 Console.WriteLine("Connection Timeout/Ceiling Hit/Failure {0} / {1} / {2} ", iConnectionTimeouts, iConnectionCeilingHit, iConnectionFailure);
\r
181 Console.SetCursorPosition(0, 15);
\r
182 Console.WriteLine("Other Failure {0} ", iFailure);
\r
183 Console.SetCursorPosition(0, 16);
\r
184 Console.WriteLine("Connection Retries {0} ", iConnectionRetries);
\r
185 Console.SetCursorPosition(0, 17);
\r
186 Console.WriteLine("Average Client CPU All/User/Sys {0}% / {1}% / {2}% ", Math.Round((fCpuAll / iSamples), 2), Math.Round((fCpuUse / iSamples), 2), Math.Round((fCpuSys / iSamples), 2));
\r
188 Console.SetCursorPosition(0, 23);
\r
189 Console.WriteLine("{0} s ", (Convert.ToInt32(duration.TotalSeconds) + 1));
\r
198 Console.SetCursorPosition(0, 4);
\r
199 Console.WriteLine("Running Clients {0} ", iRunningClients);
\r
200 Console.SetCursorPosition(0, 5);
\r
201 Console.WriteLine("Running Transactions {0} : {1} max ", iRunningTransactions, iMaxRunning);
\r
203 Console.SetCursorPosition(0, 7);
\r
204 Console.WriteLine("Completed Queries {0} : {1} qps ", iCompletedQueries, (iCompletedQueries / (Convert.ToInt32(duration.TotalSeconds) + 1)));
\r
205 Console.SetCursorPosition(0, 8);
\r
206 Console.WriteLine("Completed Transactions {0} : {1} tps ", iCompletedTransactions, (iCompletedTransactions / (Convert.ToInt32(duration.TotalSeconds) + 1)));
\r
207 Console.SetCursorPosition(0, 9);
\r
208 Console.WriteLine("Completed Iterations {0} / {1} ", iCompletedIterations, (iIterations * iClients));
\r
210 Console.SetCursorPosition(0, 11);
\r
211 Console.WriteLine("Maximum Transaction+Read Time {0} ms : {1} Running ", iMaxTransDuration, iRunningAtMax);
\r
212 Console.SetCursorPosition(0, 12);
\r
213 Console.WriteLine("Minimum Transaction+Read Time {0} ms : {1} Running ", iMinTransDuration, iRunningAtMin);
\r
215 Console.SetCursorPosition(0, 14);
\r
216 Console.WriteLine("Connection Timeout/Ceiling Hit/Failure {0} / {1} / {2} ", iConnectionTimeouts, iConnectionCeilingHit, iConnectionFailure);
\r
217 Console.SetCursorPosition(0, 15);
\r
218 Console.WriteLine("Other Failure {0} ", iFailure);
\r
219 Console.SetCursorPosition(0, 16);
\r
220 Console.WriteLine("Connection Retries {0} ", iConnectionRetries);
\r
221 Console.SetCursorPosition(0, 17);
\r
222 Console.WriteLine("Average Client CPU All/User/Sys {0}% / {1}% / {2}% ", Math.Round((fCpuAll / iSamples),2), Math.Round((fCpuUse / iSamples),2), Math.Round((fCpuSys / iSamples),2));
\r
224 Console.SetCursorPosition(0, 23);
\r
225 Console.WriteLine("{0} s ", (Convert.ToInt32(duration.TotalSeconds) + 1));
\r
227 Info("==========================================================", iLogLevel, bVerboseScreen);
\r
228 Info(" Running Clients " + iRunningClients, iLogLevel, bVerboseScreen);
\r
229 Info(" Running Transactions " + iRunningTransactions, iLogLevel, bVerboseScreen);
\r
230 Info(" Completed Queries " + iCompletedQueries + " : " + (iCompletedQueries / (Convert.ToInt32(duration.TotalSeconds) + 1)) + " qps", iLogLevel, bVerboseScreen);
\r
231 Info(" Completed Transactions " + iCompletedTransactions + " : " + (iCompletedTransactions / (Convert.ToInt32(duration.TotalSeconds) + 1)) + " tps", iLogLevel, bVerboseScreen);
\r
232 Info(" Completed Iterations " + iCompletedIterations + " / " + (iIterations * iClients), iLogLevel, bVerboseScreen);
\r
233 Info(" Maximum Transaction+Read Time " + iMaxTransDuration + " ms", iLogLevel, bVerboseScreen);
\r
234 Info(" Minimum Transaction+Read Time " + iMinTransDuration + " ms", iLogLevel, bVerboseScreen);
\r
235 Info(" Connection Timeout/Ceiling Hit/Failure " + iConnectionTimeouts + " / " + iConnectionCeilingHit + " / " + iConnectionFailure, iLogLevel, bVerboseScreen);
\r
236 Info(" Other Failure " + iFailure, iLogLevel, bVerboseScreen);
\r
237 Info(" Connection Retries " + iConnectionRetries, iLogLevel, bVerboseScreen);
\r
238 Info(" Total Time " + Convert.ToInt32(duration.TotalSeconds) + 1, iLogLevel, bVerboseScreen);
\r
239 Info(" Max Concurrent Transactions " + iMaxRunning, iLogLevel, bVerboseScreen);
\r
240 Info(" Average Client CPU All/User/Sys " + Math.Round((fCpuAll / iSamples), 2) + "% " + Math.Round((fCpuUse / iSamples), 2) + "% " + Math.Round((fCpuSys / iSamples), 2) + "%", iLogLevel, bVerboseScreen);
\r
241 Info("==========================================================", iLogLevel, bVerboseScreen);
\r
243 iMeanTransactionDuration = 0;
\r
244 iStandatdDeviation = 0;
\r
246 for (int i = 0; i < iTransactionTimeIndex; i++)
\r
248 iMeanTransactionDuration = (aTransactionTimeArray[i] + iMeanTransactionDuration);
\r
250 iMeanTransactionDuration = (iMeanTransactionDuration / iTransactionTimeIndex);
\r
252 for (int i = 0; i < iTransactionTimeIndex; i++)
\r
255 iStandatdDeviation = (Math.Pow((aTransactionTimeArray[i] - iMeanTransactionDuration), 2) + iStandatdDeviation);
\r
257 iStandatdDeviation = Math.Sqrt(iStandatdDeviation / iTransactionTimeIndex);
\r
259 CsvLogWriter("\"" + sServerDescription + "\"," + iClients + "," + iIterations + "," + iMaxTransDuration + "," + iMinTransDuration + "," + iRunningAtMax + "," + iRunningAtMin + "," + iMeanTransactionDuration + "," + iStandatdDeviation + "," + (iCompletedTransactions / (Convert.ToInt32(duration.TotalSeconds) + 1)) + "," + (iCompletedQueries / (Convert.ToInt32(duration.TotalSeconds) + 1)) + "," + iMaxRunning + "," + (Convert.ToInt32(duration.TotalSeconds) + 1) + "," + (fCpuAll / iSamples));
\r
263 public static void ClientWorker(object iThread)
\r
266 Info("Starting client thread " + iThread.ToString(), iLogLevel, bVerboseScreen);
\r
268 Random random = new Random();
\r
272 int iRandomStmt = 0;
\r
273 int iRandomTran = 0;
\r
274 NpgsqlConnection conn = null;
\r
275 if (!bConnPerIteration)
\r
277 conn = new NpgsqlConnection(sConn);
\r
281 for (int i = 0; i < iIterations; i++)
\r
285 DateTime startTime = DateTime.Now;
\r
286 if (bConnPerIteration)
\r
288 conn = new NpgsqlConnection(sConn);
\r
292 //foreach (DataRow transaction in dsTransactions.Tables[0].Rows)
\r
294 foreach (XmlNode node in xmlTransactions.SelectNodes("//transaction"))
\r
297 XmlNode randomtransaction = node.Attributes["random"];
\r
298 if (randomtransaction != null && node.Attributes["random"].Value.Trim().ToLower() == "true")
\r
300 iRandomTran = random.Next(0, 2);
\r
303 if (iRandomTran == 0)
\r
305 NpgsqlTransaction tran = conn.BeginTransaction();
\r
306 DateTime beginTime = DateTime.Now;
\r
308 lock (oTransCounterLock)
\r
310 iRunningTransactions++;
\r
313 //foreach (DataColumn column in dsTransactions.Tables[0].Columns)
\r
315 foreach (XmlNode subnode in node.SelectNodes("//sql"))
\r
318 XmlNode randomsql = subnode.Attributes["random"];
\r
319 if (randomsql != null && subnode.Attributes["random"].Value.Trim().ToLower() == "true")
\r
321 iRandomStmt = random.Next(0, 2);
\r
324 if (iRandomStmt == 0)
\r
326 sSql = subnode.InnerText;
\r
327 //NpgsqlCommand command = new NpgsqlCommand(transaction[column].ToString().Replace("#client_id#", iThread.ToString()), conn, tran);
\r
328 NpgsqlCommand command = new NpgsqlCommand(sSql.Replace("#client_id#", iThread.ToString()), conn, tran);
\r
329 NpgsqlDataReader dr = command.ExecuteReader();
\r
331 iCompletedQueries++;
\r
334 //Just pull the data back into our dataset (but we don't care about it)
\r
339 Info("Client " + iThread.ToString() + " Transaction = " + iTransOn + " Statement = " + iSqlOn + " SQL = \"" + sSql + "\" Running", iLogLevel, bVerboseScreen);
\r
346 Info("Client " + iThread.ToString() + " Transaction = " + iTransOn + " Statement = " + iSqlOn + " Skipping as random statement = true", iLogLevel, bVerboseScreen);
\r
352 DateTime commitTime = DateTime.Now;
\r
353 TimeSpan transactionDuration = commitTime - beginTime;
\r
355 if (iRunningClients == iClients)
\r
358 if (transactionDuration.TotalMilliseconds > iMaxTransDuration)
\r
360 lock (oTransDurationLock)
\r
362 iMaxTransDuration = transactionDuration.TotalMilliseconds;
\r
363 iRunningAtMax = iRunningTransactions;
\r
366 if (transactionDuration.TotalMilliseconds < iMinTransDuration)
\r
368 lock (oTransDurationLock)
\r
370 iMinTransDuration = transactionDuration.TotalMilliseconds;
\r
371 iRunningAtMin = iRunningTransactions;
\r
375 lock (oTransCounterLock)
\r
377 if (iRunningTransactions > iMaxRunning)
\r
379 iMaxRunning = iRunningTransactions;
\r
381 iCompletedTransactions++;
\r
382 aTransactionTimeArray[iTransactionTimeIndex] = transactionDuration.TotalMilliseconds;
\r
383 iTransactionTimeIndex++;
\r
384 iRunningTransactions--;
\r
391 Info("Client " + iThread.ToString() + " Transaction = " + iTransOn + " Skipping as random transaction = true", iLogLevel, bVerboseScreen);
\r
396 lock (oIterationCounterLock)
\r
398 iCompletedIterations++;
\r
401 if (bConnPerIteration)
\r
406 DateTime stopTime = DateTime.Now;
\r
407 TimeSpan duration = stopTime - startTime;
\r
408 Info("Client " + iThread.ToString() + " Iteration " + i.ToString() + " Iteration Time " + duration.TotalMilliseconds + " ms (including application read)", iLogLevel, bVerboseScreen);
\r
411 catch (Exception e)
\r
413 if (String.Compare(e.Message, 0, "A timeout has occured", 0, 21) == 0)
\r
415 iConnectionTimeouts++;
\r
417 else if (String.Compare(e.Message, 0, "Failed to establish a connection", 0, 32) == 0)
\r
419 iConnectionFailure++;
\r
421 else if ((e.Message == "ERROR: 08P01: no more connections allowed") || (e.Message == "FATAL: 53300: connection limit exceeded for non-superusers") || (e.Message == "FATAL: 53300: sorry, too many clients already"))
\r
423 iConnectionCeilingHit++;
\r
429 Info("Client " + iThread.ToString() + " Iteration " + i.ToString() + " FAILURE " + e.Message + " TARGET " + e.TargetSite + " INFO = " + e.ToString(), iLogLevel, bVerboseScreen);
\r
430 if (bOnFailureRetry)
\r
433 iConnectionRetries++;
\r
438 if (iSleepTime > 0)
\r
440 Thread.Sleep(iSleepTime);
\r
443 if (!bConnPerIteration)
\r
449 public static void Info(string sInfoText, int iInfoLevel, bool bScreen)
\r
451 if (iInfoLevel >= 1)
\r
453 AddLog(sInfoText);
\r
457 Console.WriteLine(sInfoText);
\r
461 public static void AddLog(string sLogText)
\r
463 DateTime currTime = DateTime.Now;
\r
465 if (sLogText.Length != 0)
\r
469 aLogArray[iLogIndex] = currTime.ToString(timeStamp) + " : " + sLogText;
\r
475 public static void LogWriter()
\r
477 if ((sLogFile != "") && (iLogLevel >=1))
\r
479 FileStream fs = new FileStream(sLogFile, FileMode.OpenOrCreate, FileAccess.Write);
\r
480 StreamWriter m_streamWriter = new StreamWriter(fs);
\r
481 m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
\r
483 for (int i = 0; i < iLogIndex; i++)
\r
485 m_streamWriter.WriteLine(aLogArray[i]);
\r
488 m_streamWriter.Flush();
\r
489 m_streamWriter.Close();
\r
493 public static void CsvLogWriter(string sLogText)
\r
495 bool bWriteHeader = false;
\r
497 if (sCsvLogFile != "")
\r
499 if (!File.Exists(sCsvLogFile))
\r
501 bWriteHeader = true;
\r
504 FileStream fs = new FileStream(sCsvLogFile, FileMode.OpenOrCreate, FileAccess.Write);
\r
505 StreamWriter m_streamWriter = new StreamWriter(fs);
\r
506 m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
\r
510 m_streamWriter.WriteLine("Server name, Clients, Iterations/client, Max transaction duration (ms), Min transaction duration (ms), Concurrent transactions at max duration, Concurrent transactions at min duration, Mean transaction duration (ms), Transaction duration standard deviation (ms), tps, qps, Max concurrent transactions, Total time (s), Avg CPU Time %");
\r
512 m_streamWriter.WriteLine(sLogText);
\r
514 m_streamWriter.Flush();
\r
515 m_streamWriter.Close();
\r
519 //public static DataSet readTransactionsFile(string sTransactionsFile)
\r
520 public static XmlDocument readTransactionsFile(string sTransactionsFile)
\r
522 DataSet ds = new DataSet();
\r
523 XmlDocument transfile = new XmlDocument();
\r
526 //GA ds.ReadXml(sTransactionsFile, XmlReadMode.InferSchema);
\r
527 transfile.Load(sTransactionsFile);
\r
529 catch (Exception e)
\r
531 Info("Error reading transaction file " + e.ToString(), iLogLevel, bVerboseScreen);
\r