Это серия статей, которые я пишу, которые охватывают четыре различных метода профилирования приложений в Visual Studio. Эти методы:
Производительность приложения — это ключевой элемент, который следует проанализировать и оптимизировать до фактического публичного выпуска. Microsoft Visual Studio 2010 поставляется со встроенными инструментами профилирования, которые предлагают разработчикам возможность анализировать производительность своих приложений на основе множества факторов. Динамический анализ кода (профилирование) позволяет находить части приложения, которые необходимо оптимизировать для достижения лучшей производительности.
ПРИМЕЧАНИЕ. Инструменты профилирования недоступны в выпусках Visual Studio 2010 Express и Professional. Подробности здесь .
Настройка примера приложения
Перед выполнением фактического анализа я настроил пример многопоточного приложения, которое будет выполнять набор операций с данными (ввод-вывод, извлечение данных через веб-сервис). Это простое консольное приложение с
методом Main и дополнительным
методом Get , которое получает фактические данные из Интернета.
Метод
Get, о котором я говорю, выглядит следующим образом:
static void Get(object state)
{
List<string> cities = new List<string>();
XmlDocument doc = new XmlDocument();
doc.Load(string.Format("http://www.webservicex.net/uszip.asmx/GetInfoByState?USState={0}", state.ToString()));
foreach (XmlNode node in doc.SelectSingleNode("NewDataSet"))
{
XmlNode childNode = node.SelectSingleNode("CITY");
string city = childNode.InnerText;
if (!cities.Contains(city))
{
cities.Add(city);
}
}
foreach (string city in cities)
Trace.WriteLine(city + ", " + state);
}
Это тот же метод, который я использовал для тестирования в
этой статье, и мне нравится использовать его в качестве примера ресурсоемкого процесса. В моем приложении я собираюсь запустить несколько потоков, которые будут вызывать этот метод и отображать (и записывать в файл) полученные данные.
Так что для
метода Main в моем консольном приложении я использую код ниже:
static void Main(string[] args)
{
TextWriterTraceListener tl = new TextWriterTraceListener("D:\\Temporary\\string.txt");
ConsoleTraceListener cl = new ConsoleTraceListener(false);
Trace.Listeners.Add(tl);
Trace.Listeners.Add(cl);
ThreadPool.QueueUserWorkItem(Get, "TX");
ThreadPool.QueueUserWorkItem(Get, "KS");
ThreadPool.QueueUserWorkItem(Get, "CA");
ThreadPool.QueueUserWorkItem(Get, "VA");
ThreadPool.QueueUserWorkItem(Get, "WA");
Console.Read();
}
Если я запускаю приложение, я вижу длинный список городов, которые возвращаются и отображаются на экране в хаотичном порядке, поскольку потоки выполняются в произвольном порядке, и некоторые из них заканчиваются раньше других.
Все готово для анализа производительности, поэтому перейдем к следующему шагу
Отслеживание показателей эффективности
Чтобы начать анализ, вам нужно запустить мастер производительности (из меню анализа):
Вам будет предложено выбрать метод анализа из четырех возможных:
Я расскажу о каждом из возможных методов профилирования в моих следующих статьях, но здесь я специально рассмотрю выборку процессора
Выполнение операции
CPU sampling collects information on how the application impacts the CPU performance, both as a single unit and as a set of separate function calls. It allows the developer to see what parts of the code are the most expensive, CPU-wise.
The next step in the Performance Wizard is choosing the project or application that needs to be profiled.
Since we are working with the current console application project, it is selected as the default item. If the solution that is currently open contains more than one project, each of them will be listed there and you will be able to select more than one project to track performance for.
In case you do not want to work with the existing project, you can bind the wizard to an executable or to a ASP.NET or JavaScript application.
NOTE: If you point to a unmanaged executable, you will only see the end result as a set of calls to system libraries and the performance indicators for the whole process, rather than functions. If you are binding to an obfuscated executable, you won’t be able to look at the source code as well.
Now to the last step, and here you are able to launch the profiling session.
Chances are that you aren’t launching Visual Studio as an administrator (with elevated permissions). In this case, once you decide to start the profiling session, you could encounter a message like this:
Click Yes and the profiling session will be started. The application will run just like any other time:
However, Visual Studio will be in process of profiling the current application:
Analyzing the results
Once completed, the final report should look similar to this:
And here is the place where you can take a look at what parts of your code impact the CPU performance most.
First of all, the Hot Path is showing you the function call path that is the most “expensive” – the one that has the biggest impact on the CPU load for your specific application:
In my case, this would be Trace.WriteLine inside the Get method, since it is called very often — for every city that is inside the list the string is printed out on the screen and in a text file. If you click on Trace.WriteLine in this list, you will open up a more detailed report on the function call:
The detailed report can give you information on CPU loads based on various calls inside the researched function. Also, you can clearly see the code part that is the most consuming:
You are able to switch between the sample percentage and the actual number of samples by changing the view from Inclusive Samples % to Inclusive Samples. Now you might be asking what Inclusive might mean here.
When a sample is taken, basically it grabs a snapshot of the call stack. When the analyzed function was on top of the stack, it counts towards the inclusive sample. If it was anywhere else in the stack, it counts towards the inclusive sample.
In the main report window, you are also able to see the functions doing the most individual work (called most often). Here, only the exclusive sample is called, therefore when the function was on top of the call stack.
NOTE: The data presented in the profiling report relates to the CPU as a whole. Via the default CPU sampling report you are not able to see the performance based on specific cores, for a multicore system.