StaticDynamicAnalysisLab - CSET Sharepoint Site

advertisement
Oregon Institute of Technology
Static Code Analysis
Goals:





Run static code analysis as part of a build
Know how to exclude or suppress rule violations
Know how to fix rule violations
Associate a rule violation with a work item
Create a check-in policy that mandates a successful static code analysis first
Overview:
Syntactically correct code that passes all the compiler checks may still have issues that need to
be resolved. If best practices weren't employed then code may not perform well, may not be
scalable, or may not be secure. Such code is an accident waiting to happen later on in the project
lifecycle. For this reason, code needs to be reviewed. Static code analysis allows code to be
reviewed early and often during development thus saving time and resources later on in the
project lifecycle.
Part 1: The basics of running code analysis
1. Here you will run the static code analyzer as part of a build. You will learn how to get
help about a rule violation and use this information to decide whether to exclude or
suppress a rule, whether to set a rule violation as an error rather than a warning, and how
to fix a rule violation.
2. Create a subdirectory in c:\ and name it StaticCodeAnalysis. Download CalcDemo.zip
from the SharePoint site into the new StaticCodeAnalysis directory. Unzip the file and
familiarize yourself with the code (there isn’t much there!).
3. Add a new subfolder in your Team Project’s SCC repository and name it
StaticCodeAnalysis. Create a workspace mapping from this folder to the directory with
the same name on your c: drive. Make this workspace mapping current. Right click on
the solution and check the code into source control.
4. Open up the project properties for Calc and set up code analysis for builds. Select the
“Microsoft All Rules” ruleset. Do a build and check code analysis results.
5. The next thing to consider is whether there are any rules to exclude from static analysis.
Are there any rules you feel might be irrelevant? If so, open the “Microsoft All Rules”
ruleset and deselect the rule or rule group to exclude. Those rule violations should
disappear. You will need to save your changes in your own custom ruleset. Make sure
you select your custom ruleset is selected and do a build.
6. Rather than exclude the rule altogether, you may just want to suppress it. You can do this
by right-clicking on the rule violation and selecting the "Suppress message(s)" menu
item. Try suppressing rules that correspond to rule violations that you want to suppress.
Suppress one rule in the source and another one in the GlobalSuppressions.cs file. Note:
if the rule does not correspond to specific code in a .cs file, your only option will be the
GlobalSuppressions.cs file.
7. Now take a look at the remaining rule violations and decide whether they should stay
warnings or changed to errors (if you feel they are serious enough to stop the build
process). To do this, open your custom ruleset and change the rule or rule group status
from "Warning" to "Error" by clicking on it. Save your changes.
8. Finally, actually fix all code that causes any rule violations. When you can perform a
clean build on the project, you are done. Add your ruleset file to your solution and check
in all pending changes.
Part 2: Integration between static code analysis and Team Foundation Server
1. In part 2, you will associate a work item with a rule violation and create a check-in policy
that mandates a successful static code analysis must run before files are checked-in to
version control.
2. Modify your code so that you have a couple “error” rule violations and run static code
analysis again.
3. Right-click on a rule violation and select the "Create Work Item->Task" menu item. Set
the "Activity" to be "Development" and assign the work item to yourself. Check in your
code.
4. Run the "My Tasks" query from Team Explorer to verify that the work item was added.
5. Add the Code Analysis check-in policy. Select your custom ruleset (in source control) to
configure static code analysis.
6. Make a small change to your code that will cause a code analysis error. Attempt to check
it in. What happens?
7. Fix your static code analysis error and check-in again. What happens? It should succeed,
as the check-in policy dictates that static code analysis should succeed (no errors but
warnings are OK) before check-in occurs.
Part 3: Deploying a Custom Rule
1. Download and build the CustomCodeAnalysisRules project from the sharepoint site.
Take some time to familiarize yourself with the code. Note the FXCop namespace
Microsoft.FxCop.Sdk. Note the references to the required FXCop assemblies FxCopSdk
and Microsoft.Cci. They are all located under the C:\Program Files (x86)\Microsoft
Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop directory. Take a look at the
XML file that provides the UI information for the rule. (Note: Depending on your op
sys…the files may be located in different—but similar paths)
2. After you are familiar with the code deploy the rule assembly (dll file) to where FxCop
looks for it: C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Static
Analysis Tools\FxCop\Rules.
3. Now introduce a public field in the calc.h class, run code analysis and see if the rule
violation appears when you run static code analysis. (Note: if it doesn’t, make sure the
rule shows up in the code analysis section of the calc.dll properties and is checked.)
Part 4: Dynamic Code Analysis
Goals:



Set up a performance session
Use the reports from the sampling profiler to predict problem areas
Use the reports from the instrumentation profiler to narrow down and fix problem areas
Overview:
In this part of the lab, you will use the Visual Studio for Team Developer Edition's profiler tool
to find performance hotspots in some poorly written code.
Setting up an instrumentation performance session
Download the PerformanceStarterCodeCSharp.zip file from the SharePoint site and familiarize
yourself with the code. Have a quick look at how the test harness application seeds the
StockHelper class with some pseudo-random Stock updates and then calls the StockHelper class
to perform certain operations. For each stock, it finds how many stock updates were above a
certain price and then calculates the average price and standard deviation of prices.
After looking at the code, you probably have a feeling that it has performance issues. We will
use the profiler tool to investigate. Be sure to rename all your profile reports appropriately.
Under the Analyze tab, select Performance and Diagnostics. Follow the wizard steps to add a
performance session to your solution. Ensure that the performance session is using
instrumentation and both the .exe and .dll projects (targets) are being analyzed.
Launch the performance session and inspect the results. What do you notice?
Take any of the "Top Exclusive Sampled Functions" and inspect them more closely as this is
where most samples were taken and hence most time was spent. Try and figure out where they
are being called from.
Often, it is helpful to have a performance report capturing object allocation. Rename your (only)
profiling report to something meaningful. Right click on the performance session and select
properties. Ensure that the performance session is using instrumentation and capturing memory
allocation and lifetime information.
Launch the performance session and inspect the results. What do you notice? Does this point to
excessive memory usage for certain types? Does it point to a particular method as the culprit?
Before going further in the lab, rename this report something meaningful.
There seem to be a lot of Stock instances and string instances. Are these all really necessary? The
performance sessions point to the StockHelper->GetStockDisplayString and StockHelper>GetFromStockHistoryWithHigherValue functions as likely culprits.
Take a look at the code for these methods and try figuring out what the problems are and how
they could be fixed.
Here are a couple hints:
Look for inefficient string concatenation allocating far too many temporary objects. Consider
using the StringBuilder class.
Look for inefficient string comparisons. String.Equals uses the default version of String.Compare
which compares with regard to culture. If this is not necessary, consider using a more targeted
version of String.Compare.
Look for unnecessary boxing/unboxing of the Stock value type. Note: the ArrayList collection
holds and returns Object references. Consider using List<>.
Look at the looping code, e.g. repeatedly accessing the properties of an object for every loop
iteration when they don't change for any loop iteration.
Sample Code follows:
public Stock[] GetFromStockHistoryWithHigherValue(Stock stock)
{
List<Stock> tmp = new List<Stock>();
string name = stock.Name;
int price = stock.Price;
foreach (Stock s in stocks)
{
if (string.Compare(s.Name, name, StringComparison.Ordinal) == 0 && s.Price > price)
tmp.Add(s);
}
return tmp.ToArray();
}
public string GetStockDisplayString(Stock[] stocks)
{
int len = stocks.Length;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++)
{
sb.Append(stocks[i].Name); sb.Append("("); sb.Append(stocks[i].Price);
sb.Append(")");
if (i != len - 1)
sb.Append(",");
}
return sb.ToString();
}
Modify your code and run performance sessions for both timing and memory allocation reports.
Compare the new report results to your baseline reports.
Download