How to plot how variables change in Visual Studio - c#

oes anyone know a way to plot how a watched variable changes over time in Visual Studio 2010? I.e. if you had the following code
double someVariable;
for ( int i = 0; i < 20; i++)
{
someVariable = Math.Pi() * i;
}
and you watched 'someVariable' in the ide you could step through the code and watch how it grows with each step. I would like to be able to run through the loop and plot what that variable did with out having to manually step through it. I am doing a lot of math and sometimes watching how variables change is really useful and insightful.
More info:
I have a bunch of slightly different solvers and depending on the problem I am troubleshooting I would like to watch different variables to see where the problems are occurring. I currently put log these variables to a log file but it slows down the solver significantly and I have to spend a decent amount of time changing debug code to track down problems. I am looking for a slicker way to do this that is IDE centric. Sort of a Visualizer on steroids.

How about using Tracepoints? In VS 2008 (it's somewhat different in VS 2010) you just add a normal breakpoint, then right-click on it, then select "When Hit...".
In the subsequent dialog box, check "Print a message" and enter something like
someVariable = {someVariable}
This will just output its value to the output window in the IDE.
Screenshot:

Easy way? None.
But you can code it yourself..
Use property.
In setter put code, that will log change in some collection. Possibly save time too.
Use some plotting control to plot this collection
Edit:
If you dont want to create property, you can create some kind of generic class, that will have this property and has some kind of internal logging logic.

Use Perfmon and publish that value to a counter that perfmon can read. Perfmon does all the plotting etc. You just need to publish to perfmon. Unfrotunately it is not very well documented and is not trivial. (well, at least it wasn't trivial for unmanaged c++ when I was looking into it)
I did this a while back and used some classes published in an old MSJ article. (ca 1998 or so)
I will try to find some online docs.
See this question for some links
This may also be useful
If you find a solution or this works for you please let us know.

Hopefully someone will come up with a better answer, but here is what I did in a similar situation...
I output the values, in CSV format, to the console. From there, I would copy and paste into Excel, and let Excel do some graphing for me. It worked quite well, but was a complete hassle during a caffeine-driven development session.

Can't you just define and array and write someVariable to array[i] inside the loop? Then you could reference it after you're done.
double[] x = new double[20];
double someVariable;
for ( int i = 0; i < 20; i++)
{
someVariable = Math.Pi() * i;
x[i] = someVariable;
}

I've found SpPerfChart very easy to use and helpful. Simply add the user control and input your changing data to it. You'll get a graphical plot of whatever number you input realtime.

Related

Trouble referencing labels with Active Reports

Ok, so to start off, this is my first time working with C#, and the top it off I am attempting to work with it in a report editor for MYOBs AEPM software, which doesn't exactly give me a lot of info or flexibility. What I have been able to work out is that it uses some version of Data Dynamics Active Reports, but not sure which one. I also cannot seem to figure out what naming they have used for much of the report. Anyway, back to the main issue.
I am needing to add some calculations to the report that the visual editor wont allow me to do(it is restricted to Count, Sum, Min, Max, Avg, Var, so not really helpful). Now the calculations are pretty simple(One is a total x .7, and the other being the result of the first x 74 but this value might be changed in the future). Figured the best way would be to just have 2 text boxes with a value in each of them of "0", and then just once the main report is pretty much done run the calculations and replace the values of the two text boxes. So I made the text boxes in the appropriate section and labelled them CalcTotal1 and CalcTotal2.
Now in the editor it allows me to select the object and an event to trigger it, so selected ReportFooter as the object and AfterPrint as the event. I then just put in a line to chance the CalcTotal1 value and tried to generate the report resulting in the following error:
Error Message: Report Script Compile Error on line 8 Error = The name 'CalcTotal1' does not exist in the current context
public void ReportFooter_AfterPrint()
{
CalcTotal1.Text = "Hello";
}
I have tried looking at the documentation for Active Reports but I am not having much luck, so any ideas would be incredibly welcome.
just add "this" word in the code like
this.CalcTotal1.Test = "Hello";
http://helpcentral.componentone.com/nethelp/AR8Help/AR8_HelpOnlineEN/Scripts.html provides some more tips.
The MYOB AE PM feature referred to is called Smart Reports.
I was able to replicate the error and consequently resolved the problem by using the following syntax:
((TextBox)rpt.Sections["Detail"].Controls["TextBox2"]).Text= "$2000.00";
eg:
public void Detail_AfterPrint()
{
((TextBox)rpt.Sections["Detail"].Controls["TextBox2"]).Text= "$2000.00";
}

Using Excel.XlLegendPosition.xlLegendPositionCustom in C#

Has anyone any idea how to use Excel.XlLegendPosition.xlLegendPositionCustom to specifically position the legend of a chart? Currently, I'm using
chart.Legend.Position = Excel.XlLegendPosition.xlLegendPositionBottom;
which does exactly what one would expect. Right up until the time when you try and print the chart. THEN it places the legend pretty much where ever it wants -- which isn't where I need it to be.
I've checked the MSDN and every other site I could think of. The best Microsoft can come up with is as follows:
xlLegendPositionCustom: A custom position.
There are no examples that I could find that show how to use this.
Thanks for any help.
Okay, it doesn't seem as if anyone has encountered this particular issue -- or needed to use the command. No worries, I appreciate folks taking the time to look at the question.
I did find a workaround that allows you to position the legend using points. It appears if you use the preset positioning options (like Excel.XlLegendPosition.xlLegendPositionBottom), Excel positions the legend based on whatever magic MS uses to figure these things out. Since I couldn't figure out how to use the Excel.XlLegendPosition.xlLegendPositionCustom, I played around with the other commands and found these:
chart.Legend.Left = 375;
chart.Legend.Top = 450;
Those commands will take an int (I used 374 and 450) and using them, you can force the position of the legend to anywhere on the chart.
I don't think you can set it to xlLegendPositionCustom, it's read-only, i.e. when you 'ask'(Debug.Print ActiveChart.Legend.Position), after setting ActiveChart.Legend.Left/ActiveChart.Legend.Top you get -4161 which is xlLegendPositionCustom.

How do I learn enough about CLR to make educated guesses about performance problems?

Yes, I am using a profiler (ANTS). But at the micro-level it cannot tell you how to fix your problem. And I'm at a microoptimization stage right now. For example, I was profiling this:
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
packedCells.Add(Data[x, y].HasCar);
packedCells.Add(Data[x, y].RoadState);
packedCells.Add(Data[x, y].Population);
}
}
ANTS showed that the y-loop-line was taking a lot of time. I thought it was because it has to constantly call the Height getter. So I created a local int height = Height; before the loops, and made the inner loop check for y < height. That actually made the performance worse! ANTS now told me the x-loop-line was a problem. Huh? That's supposed to be insignificant, it's the outer loop!
Eventually I had a revelation - maybe using a property for the outer-loop-bound and a local for the inner-loop-bound made CLR jump often between a "locals" cache and a "this-pointer" cache (I'm used to thinking in terms of CPU cache). So I made a local for Width as well, and that fixed it.
From there, it was clear that I should make a local for Data as well - even though Data was not even a property (it was a field). And indeed that bought me some more performance.
Bafflingly, though, reordering the x and y loops (to improve cache usage) made zero difference, even though the array is huge (3000x3000).
Now, I want to learn why the stuff I did improved the performance. What book do you suggest I read?
CLR via C# by Jeffrey Richter.
It is such a great book that someone stolen it in my library together with C# in depth.
The CLR is not involved at all here, this should all be translated to straight machine code without calls into the CLR. The JIT compiler is responsible for generating that machine code, it has an optimizer that tries to come up with the most efficient code. It has limitations, it cannot spend a large amount of time on it.
One of the important things it does is figuring out what local variables should be stored in the CPU registers. That's something that changed when you put the Height property in a local variable. It possibly decided to store that variable in a register. But now there's one less available to store another variable. Like the x or y variable, one that's critical for speed. Yes, that will slow it down.
You got a bad diagnostic about the outer loop. That could possibly be caused by the JIT optimizer re-arranging the loop code, giving the profiler a harder time mapping the machine code back to the corresponding C# statement.
Similarly, the optimizer might have decided that you were using the array inefficiently and switched the indexing order back. Not so sure it actually does that, but not impossible.
Anyhoo, the only way you can get some insight here is by looking at the generated machine code. There are many decent books about x86 assembly code, although they might be a bit hard to find these days. Your starting point is Debug + Windows + Disassembly.
Keep in mind however that even the machine code is not a very good predictor of how efficient code is going to run. Modern CPU cores are enormously complicated and the machine code is no longer representative for what actually happens inside the core. The only tried and true way is what you've already been doing: trial and error.
Albin - no. Honestly I didn't think that running outside a profiler would change the performance difference, so I didn't bother. You think I should have? Has that been a problem for you before? (I am compiling with optimizations on though)
Running under a debugger changes the performance: when it's being run under a debugger, the just-in-time compiler automatically disables optimizations (to make it easier to debug)!
If you must, use the debugger to attach to an already-running already-JITted process.
One thing you should know about working with Arrays is that the CLR will always make sure that array-indices are not out-of-bounds. It has an optimization for 1-dimensional arrays but not for 2+ dimensions.
Knowing this, you may want to benchmark MyCell Data[][] instead of MyCell Data[,]
Hm, I don't think that the loop enrolling is the real problem.
1. I'd try to avoid accessing the array Data three times per inner loop.
2. I'd also recommend, to re-think the three Add statements: you are apparently accessing a collection three times to add trivial some data. Make it only one access per iteration and add a data type containing three entries:
for (int y = 0; ... {
tTemp = Data[x, y];
packedCells.Add(new {
tTemp.HasCar, tTemp.RoadState, tTemp.Population
});
}
Another look reveals, that you are basically vectorizing a matrix by copying it into an array (or some other sequential collection)... Is that necessary at all? Why don't you just define a specialized indexer which simulates that linear access? Even better, if you only need to enumerate the entries (in that example you do, no random access required), why don't you use an adequate LINQ expression?
Point 1) Educated guesses are not the way to do performance tuning. In this case I can guess about as well as most, but guessing is the wrong way to do it.
Point 2) Profilers need to be well understood before you know what they're actually telling you. Here's a discussion of the issues. For example, what many profilers do is tell you "where the program spends its time", i.e. where the program counter spends its time, so they are almost absolutely blind to time requested by function calls, which is what your inner loop seems to consist of.
I do a lot of performance tuning, and here is what I do. I cycle between two activities:
Overall time measurement. This doesn't require special tools. I'm not trying to measure individual routines.
"Bottleneck" location. This does not require running the code at any kind of speed, because I'm not measuring. What I'm doing is locating lines of code that are responsible for a significant percent of time. I know which lines they are because they are on the stack for that percent, and stack samples easily find them.
Once I find a "bottleneck" and fix it, I go back to the first step, measure what percent of time I saved, and do it all again on the next "bottleneck", typically from 2 to 6 times. I am helped by the "magnification effect", in which a fixed problem magnifies the percentage used by remaining problems. It works for both macro and micro optimization.
(Sorry if I can't write "bottleneck" without quotes, because I don't think I've ever found a performance problem that resembled the neck of a bottle. Rather they were all simply doing things that didn't really need to be done.)
Since the comment might be overseen, I repeat myself: it is quite cumbersome to optimize code which is per se overfluous. You do not really need to explicitely linearize your matrix at all, see the comment above: Define a linearizing adapter which implements IEnumerable<MyCell> and feed it into the formatter.
I am getting a warning when I try to add another answer, so I am going to recycle this one.. :) After reading Steve's comments and thinking about it for a while, I suggest the following:
If serializing a multi-dimensional array is too slow (haven't tryied, I just believe you...) don't use it at all! It appears, that your matrix is not sparse and has fixed dimensions. So define the structure holding your cells as simple linear array with indexer:
[Serializable()]
class CellMatrix {
Cell [] mCells;
public int Rows { get; }
public int Columns { get; }
public Cell this (int i, int j) {
get {
return mCells[i + Rows * j];
}
// setter...
}
// constructor taking rows/cols...
}
A thing like this should serialize as fast as native Array does... I don't recommend hard coding the layout of Cell in order to save few bytes there...
Cheers,
Paul

Sending messages to a Flash game with C# and AutoIt

I'm making a bot for a Flash game, and I've figured out how to import all the AutoIt functions into my C# code.
string title = "Minesweeper";
string full = auto.WinGetTitle(title,"");
string handle = auto.WinGetHandle(full, "");
if (auto.WinExists(full, "") == 1)
textBox1.Text = "window exists";
addressBox.Text = full;
for (int r = 1; r < 40; r++)
{
auto.ControlClick(full, "", "", "left", 2, r * 10, r * 10);
//auto.ControlClick(handle, "", "", "left", 2, r * 10, r * 10);
}
(I'm pretty sure the uncommented one should be the one with handle and vice versa, but this works for Minesweeper.)
So it works for Minesweeper and doesn't require it to be the active window. When I try to make it work on my Flash game it requires the Internet Explorer window to be the active one. Is this something Flash requires or is there something additional that I could do to make it work when the game is minimized?
This doesn't have to be done using the AutoIt imports. I tried SendMessage from user32 at one point also, but that didn't work for Flash content at all for me.
I just tested this on a random website instead of a Flash site or Minesweeper and for some reason the code works if I execute it from within the Autoit scripting program, but not from my C# program...
June 20th, 2012: I am pretty sure this has something to do with the way the handle gets passed. I've done some tests with calling an AutoIt EXE file and using the handle I get from the C# code as an argument, I have to add an 0x to it, and also then within the AutoIt code I have to cast it from a string to an HWnd, so that could be something, in which case I don't know what to do since the imported function relies on a string input for the handle.
Something you may want to try to rule out window handle and variable handling issues. There should be no need to use WinGetTitle the "Minesweeper" window title should work fine. According to my AutoIt v3 Window Info tool in Windows 7 the title and class of Minesweeper window are both Minesweeper. So hard coding
auto.ControlClick("[TITLE:Minesweeper;
CLASS:Minesweeper], "", "", "left", 2,
r * 10, r * 10);
might work. For more on how that works see Advanced Window Descriptions in the AutoIt help file. If this still isn't working look up WinTitleMatchMode in the help file. It allows you to set up some rules for leniency in window title matching that could make this easier for you.
AutoIt X is AutoIt's DLL/COM control version it is how you would add AuotIt to any language that has DLL/COM support. In case anyone else was wondering how you would use AutoIt in C#. Unfortunately AutoIt X often lags behind in development and testing from the main language. Although have no reason to think your problem is caused by a bug just giving some background on the AutoItX project. If you haven't already you should post a copy of this question to the ActiveX/COM Help and Support (AutoItX) forum. One the the best things about AutoIt in my experience over the years is the community (which hasn't moved here much). That particular forum section is frequented by some of the developers of the language who would be happy to help.
As to your June 20th note, AutoIt treats all variables like strings until it detects that its something special. It doesn't know a value is hex unless it starts with the 0x you mentioned. This has caused all sorts of strange problems for me in the past. I have on several occasions had to add zero to a variable to get AutoIt to evaluate it correctly after. This doesn't happen often with AutoIt3 but just something to keep in mind.
If you need any AutoIt reference code plenty of members of the AutoIt forum have made Minesweeper bots you can check out and possibly see something helpful.
Make sure your running your C# program as admin. This is the only difference I can see for one method working and the other not.

String Comparison set to boolean variable

I assume this should be fine
bool prefMatch = false;
// Is the frequency the same?
prefMatch = string.Compare(user.Frequency, pref.Action.ToString()) == 0;
so if user.Frequency is "3" and pref.Action.ToString() is "3" then it should set the prefMatch to true right? I'm getting false and I've definitely checked the 2 values in the watch tab in VS 2008 just to be sure they're the same
You can just use ==
prefMath = (user.Frequency == pref.Action.ToString());
Though string.Compare will also work. I suggest there is a problem elsewhere.
-- Edit
Also, just for completeness, there is no point assigning a variable to something, and then assigning it again directly after. It's slightly confusing to do so, so better to leave it unassigned, or assign it all in one spot. This way the compiler can help you if you have a case where it doesn't get assigned like you think. It is, obviously, acceptable to assign first if you wrap the second assignment in a try/catch though.
In situations like these, it's sometimes tempting to point the finger of blame at third-party code, as you've done here. Sometimes, this is justified - but not here. String.Compare is a central, extremely-well-tested piece of the .NET Framework. It's not failing. I guarantee it.
What I find helpful in these situations is to isolate the failure. Write a small, self-contained test case that attempts to demonstrate the problem. Write it with as few dependencies as possible. Make it a stand-alone console application, if possible. Post it here. If we can take it, compile and run it, and reproduce the problem, we can help you. I'd bet money, though, that in the course of creating this test case, you'll experience a head-slapping moment - "of course!" - and realize what the problem is.
Maybe the string(s) contain unprintable characters ?
To check, I'd do something like :
byte[] b1 = System.Text.Encoding.UTF8.GetBytes(user.Frequency);
byte[] b2 = System.Text.Encoding.UTF8.GetBytes(pref.Action.ToString());
then compare the contents of b1 and b2.

Categories

Resources