|
Nope, don't know how to make it faster. I did try a few different loop approaches, but I get the impression they're being optimized down by the compiler into the same thing. They all seem to come out roughly the same speed (within a ms of each other). If you need something faster, you're going to be better off using C/C++.
And, just for kicks, I did try using raw pointer arithmetic in an unsafe context. It was still coming out slower then just looping. I found this odd...
|
|
|
|
|
You can use loop unwinding.
Alternatively, rather than indexing the pointer, you can just increment it by one (ptr++) each loop iteration and use a while loop that only checks if the pointer you are currently at matches the ending pointer.
You can also combine the two techniques. Would go something like this (some syntax and values may be wrong, but you get the idea):
byte* ptr = data;
byte* ptrEnd = data;
ptrEnd += (size - (size % 10));
while (ptr != ptrEnd)
{
*ptr = 128; ptr++;
*ptr = 128; ptr++;
*ptr = 128; ptr++;
*ptr = 128; ptr++;
*ptr = 128; ptr++;
*ptr = 128; ptr++;
*ptr = 128; ptr++;
*ptr = 128; ptr++;
*ptr = 128; ptr++;
*ptr = 128; ptr++;
}
ptrEnd += (size % 10);
while(ptr != ptrEnd)
{
*ptr = 128; ptr++;
}
I think there is also some more compact (and hard to understand, but maybe faster) syntax, but I forget it exactly. Something like this:
*(++ptr) = 128;
*(ptr++) = 128;
I think C++ C# also has an optimized array.copy function. You can fill in an array of, say, 100 values, then copy that to the "data" array a bunch of times. Or maybe you can copy the array to itself a bunch of times, each time doubling the number of elements you can copy. Would go something like this (I can't be bothered looking up the syntax right now):
Array.Copy(data, 0, length, data, length, length);
That would be 1 iteration in a loop... you'd obviously have to change the value of length each iteration. And you'd have to account for edge conditions. And it would only be useful if you were really filling the entire array with the same value.
Martin Fowler wrote: Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
|
|
|
|
|
Are you sure you want a big array filled with a single constant? if not, I urge you to investigate (and ask questions about) the actual things you want, not some mock-up. If you need a predictable content, Array.Copy would be a prime candidate (fill a smaller array first, then copy it as often as you like).
FWIW: No matter what language you use, bigger array elements (int or long) would get copied faster than smaller ones (byte) as the loop count, and the cost of the loop overhead, would decrease.
Finally, as a general comment on performance measurements, anyone proficient in language A and new to language B can easily "proof" that A is faster than B, no matter what A and B are. Half of your C# snippet can be scrapped without affecting the results (and possibly the performance either); however automatic optimizations (which exist both in the compiler and the JIT-compiler) work best when there isn't too much ballast to begin with.
|
|
|
|
|
Kevin13 wrote: The C# returns between 30 and 45 ms and the C/C++ a stable 4.2 ms.
Is there anything I can do with my C# code to speed it up?
Words of wisdom, you can code in C.
You're comparing native code to an interpreted language. Of course it's slower, what'd you expect? It's not a big deal; one can create apps quicker, and the source is more accessible than pure C would be. If .NET seems to be slow on my machine, I know I'm doing something the wrong way (like not reusing objects).
If you ever encounter the need for something "faster", then simply call your C-routines from C#.
Bastard Programmer from Hell
|
|
|
|
|
Eddy Vluggen wrote: You're comparing native code to an interpreted language
C# isn't an interpreted language. It's compiled on the machine it is run on, making it possibly faster than pre-compiled code for a more generic architecture.
My guess is that the C++ compiler is using some special optimization (e.g., MMX instructions, or loop unwinding) that the C# compiler didn't happen to implement for this scenario.
Martin Fowler wrote: Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
|
|
|
|
|
AspDotNetDev wrote: It's compiled on the machine it is run on, making it possibly faster than pre-compiled code for a more generic architecture.
Compiles to bytecode AFAIK, and runs in a VM.
AspDotNetDev wrote: My guess is that the C++ compiler is using some special optimization (e.g., MMX instructions, or loop unwinding) that the C# compiler didn't happen to implement for this scenario.
No garbage-collector thread in the background, no framework at all.
Bastard Programmer from Hell
|
|
|
|
|
Eddy Vluggen wrote: Compiles to bytecode AFAIK, and runs in a VM.
Nope. Compiles to native code and does not use a VM. See http://en.wikipedia.org/wiki/Common_Intermediate_Language#General_information. The DLL contains bytecode, but when (just before, actually) the DLL is run it gets compiled to native code.
Eddy Vluggen wrote: No garbage-collector thread in the background, no framework at all.
The garbage collector works in stages. It wouldn't slow down performance in general (e.g., 3x slower). In the OP's example, the array would likely be placed on the large object heap and would not cause compaction when the memory is released. Though, one of those stages could have caused the OP's code to appear to run 3x slower, so the OP should probably run a larger test run (say, a second or two).
Martin Fowler wrote: Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
|
|
|
|
|
AspDotNetDev wrote: The DLL contains bytecode, but when (just before, actually) the DLL is run it gets compiled to native code.
P-code to native; aight, I won't call it an interpreter again.
AspDotNetDev wrote: The garbage collector works in stages. It wouldn't slow down performance in general.
It's additional load on the CPU, as well as managing AppDomains is. The application also contains metadata that the C version does not have, and in general the "runtime" will reserve 20 Mb of memory for your app on startup.
Compare some string-operations in Delphi to C#. It simply hurts if you're concatenating a lot; but once you learn that strings are immutable and that there's a StringBuilder, things work quite nicely.
Bastard Programmer from Hell
|
|
|
|
|
Two comparable snippets;
class Program
{
static List<String> numbersList = new List<string>();
static void Main(string[] args)
{
int start = Environment.TickCount;
while (Environment.TickCount - start < 5000)
{
numbersList.Add("Tick " + Environment.TickCount);
}
Console.WriteLine(numbersList.Count);
Console.ReadKey();
}
}
procedure Test1();
var start: dword;
numbersList: TStringList;
begin
numbersList := TStringList.Create();
start := GetTickCount();
while GetTickCount() - start < 5000 do
begin
numbersList.Add('Tick ' + IntToStr(GetTickCount()));
end;
WriteLn(numbersList.Count);
numbersList.Clear;
numbersList.Free;
end;
begin
Test1();
ReadLn();
end.
C# managed to create 3.413.266 objects (in release mode, set to x86). Lazarus TCreated a 5.295.911 items without knowing about my cpu.
FWIW, if I convert the example that the TS provided to Delphi, I come out at 43 ms (included for those that want to run their own tests);
procedure Test2();
const testSize = 10000000;
var start: dword;
data : array[0..testSize] of byte;
i : integer;
begin
start := GetTickCount();
for i := 0 to testSize do
begin
data[i] := 128;
end;
WriteLn('Safe time ' + IntToStr(GetTickCount() - start) + ' ms');
end;
..and I might want to add that you should measure using timeGetTime() , not using GetTickCount . Wish I had VB6 here to give it a try, in both native and P-code versions. My first boss would disagree with the provided testcode, as there's a more efficient version;
procedure Test2();
const testSize = 10000000;
var start: dword;
data : array[0..testSize] of byte;
begin
start := GetTickCount();
FillChar(data, SizeOf(data), 128);
WriteLn('Safe time ' + IntToStr(GetTickCount() - start) + ' ms');
end;
This does it in 15 ms. That doesn't mean I'm switching back! .NET does the most things in an effective way, despite all the metadata and the wrappers. Plus, it provides a lot of convenience.
We've got profilers that work a lot better than the old timeGetTime API, and we got a lot of goodies that support building an application quickly, with a damn good performance.
Bastard Programmer from Hell
|
|
|
|
|
I Implemented the Rename Functionality, But can some one tells me the good way to implement the Undo Functionality for rename?
|
|
|
|
|
How about clarifying the scenario here:
1. is this a WinForms question, and are you using the standard WinForms TreeView provided by MS ?
2. For 'Undo:' are you talking about one level of Undo, or many levels, or levels set by the end-user while running the Application ?
best, Bill
"Beauty is in the eye of the beholder, and it may be necessary from time to time to give a stupid or misinformed beholder a black eye." Miss Piggy"
|
|
|
|
|
You shouldn't 'implement the Undo Functionality for rename'. You should implement undo as an app-wide thing which maintains a stack of commands across the whole application and knows how to undo them.
There's two ways to do undo: either you maintain the state before each operation, or you store each operation as a command which knows how to undo itself. In all but the simplest case you want to do the second way. You need to implement every action within your application as a command, where command means something like:
interface IUndoableCommand {
void Undo();
void Redo();
}
In this case, assuming your tree view is bound to some view-model level property, you would hook the NodeRenamed event (whatever it's actually called) - pseudocode:
class ItemRenameCommand : IUndoableCommand {
string oldname, newname;
INamedModel Model { get; set; }
ItemRenameCommand(INamedModel model, string oldname, string newname) {
this.oldname = oldname; this.newname = newname;
Model = model;
}
void Undo() { Model.Name = oldname; }
void Redo() { Model.Name = newname; }
}
class MainForm : Form {
...
void TreeNodeRenamed(object sender, NodeRenameEventArgs e){
IUndoableCommand renameCommand = new ItemRenameCommand(treeViewModel, e.OldName, e.NewName);
undoStack.Push(renameCommand);
}
Stack<IUndoableCommand> undoStack, redoStack;
}
(Remember, pseudocode; I can't remember how you actually hook onto the rename event of a TreeView, and it's not really the main point of the discussion, but it means that won't compile.) INamedModel is just for the Name property, you'd typically have all your view model classes implement something like that in a strongly typed environment.
One can have an argument about whether the undo/redo stacks should be in the UI (i.e. the view) or the view-model, taking a MVVM approach to structure. I tend to feel that because it represents user actions, it is part of the view.
Then, to undo, you take items off the undo stack and call .Undo() on each of them in turn, pushing them onto the redo stack. And to redo, you take items off the redo stack, move them to the undo stack and call .Redo() on each one.
The tricky bit is making sure that everything can be represented by a reversible command. For some things (simplistic example, a Reset or Randomise button) you will have to store most or all of the previous state, but avoid doing that in all cases where it is possible to do so, as storing the whole state for each undo entry is a big waste of storage.
|
|
|
|
|
Hi Bob,
This is a great answer, thanks, and, imho, far more than this as-yet-non-responsive questioner deserves, or can probably "handle."
But, I do feel that if the OP wants to implement Undo for just the Text displayed on TreeNodes, that's okay. People new to the game often need to start at a lower level of abstraction, and solving specific problems may, perhaps, lead them, later, to be able to have a "basis" for understanding higher-level abstractions and code strategies.
If the OP shows any response, I'll help he or she with a simple example of Undo with the TreeNode text.
best, Bill
"Beauty is in the eye of the beholder, and it may be necessary from time to time to give a stupid or misinformed beholder a black eye." Miss Piggy"
|
|
|
|
|
Hi Bob,
thanks, Its the one which i needed..
|
|
|
|
|
Hi everyone,
we have an GUI application that starts and observes several console processes.
Because it can be lots of processes, we are starting these console applications hidden:
Process process = new Process();
process.StartInfo.FileName = dir + @"\ConsoleApp.exe";
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
So far so good, no shell is showing up!
But if the user closes the user interface (which started these processes) all the console applications are still running. Since they should finish their job, this is more or less ok. But we would like to show each console again, so the user could stop them if necessary or watch output in each shell himself.
Any idea how to show the console applications again?
The preferred approach would be that each console application can show itself. (So they would pop up again even if the GUI simply crashed)
I have looked into the process information, but the MainWindowHandle property is set to null for the console applications, so I can't use it to show the shell.
That's also true for any other combination of startinfo properties which lead to a hidden console.
In contrast, Spy++ shows a hidden window for my hidden console app! So how to obtain the (still hidden) window's handle?
Or any other idea how to show these hidden consoles again?
Cheers, Roland
|
|
|
|
|
Try windows messages. that gets messages accross applications easily AND you let the application itself handle his own properties.
hope this helps.
V.
|
|
|
|
|
Could you please go into details a little more?
What window message would you send to whome?
ShowWindow is also just sending SW_SHOW in the end, but I would need to know the window handle of the console application before I can send it there...
Cheers, Roland
|
|
|
|
|
Look here[^]
key words were C# send window message in google.
V.
|
|
|
|
|
Oh funny reply, dude! Was the question how to send window messages in general?
As I said before, you'd have to know who is the recipient for that message, and actually THAT is the problem.
A hidden application has no idea about it's main window's hwnd. And a console application cannot set it's window title to make other apps find it by FindWindow with given title.
|
|
|
|
|
Don't be so impolite. And I gather you haven't understood my reply, at all.
I guess you'll have to figure it out for yourself then.
I'm sorry I wasn't able to make it more clearer to you.
V.
|
|
|
|
|
Sorry, but from my point of view your post was already inpolite.
I know how to google and how to send messages, I am no noob.
But if you have no window handle as recipient, you will never send messages anywhere.
And the page you linked uses Process' MainWindowHandle property which is always NULL for hidden windows. (As written in my initial post, maybe you have only scanned the first lines of it.)
No window handle, no chance to send the message.
Seems I have really to enumerate over all windows and find the hidden window that belongs to the process... what a hack...
|
|
|
|
|
There was a post on MSDN about this a while ago, How to obtain a Console Window Handle[^] which uses FindWindow to look for a known window title. It seems ok for Windows XP and I wrote a quick test (with no error checking on the Windows API calls).
public partial class ConsoleControllerForm : Form {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
[DllImport("user32.dll")]
private static extern IntPtr FindWindowW(
[In] [MarshalAs(UnmanagedType.LPWStr)] String lpClassName,
[In] [MarshalAs(UnmanagedType.LPWStr)] String WindowName);
private const String KnownConsoleTitle = "TestApp";
private IntPtr handle;
public ConsoleControllerForm() {
InitializeComponent();
}
private void StartBtn_Click(object sender, EventArgs e) {
StartProcess();
FindCmd();
}
private void FindCmd() {
handle = FindWindowW(null, KnownConsoleTitle);
ShowBtn.Enabled = handle != IntPtr.Zero;
}
private void ShowBtn_Click(object sender, EventArgs e) {
ShowWindow(handle, 1);
}
private static void StartProcess() {
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = @"TestApp.exe";
psi.UseShellExecute = true;
psi.CreateNoWindow = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
Process p = Process.Start(psi);
Thread.Sleep(1000);
}
}
Note the ProcessStartInfo properties are the only combination for which the subsequent ShowWindow actually shows the window and that TestApp.exe explicitly sets it's title to "TestApp" so I know what to look for with FindWindow.
I doubt this approach will solve your problem completely but hopefully it's given you a start.
Alan.
|
|
|
|
|
Hi Alan,
thanks for your reply!
At the moment I really make use of a combination of EnumWindows and GetWindowThreadProcessId to get my own (hidden) window's handle within the console application. But I am not happy about enumerating over all windows.
FindWindow was also my first thought... the problem was that I had no clue what the title is. The shell usually shows the console application's full path in the title. Having multiple instances running, this can be quite difficult to find a specific one.
But you made me think about the window title again, because you really hardcoded a title for a console application. First I thought I could not change it from within the console application itself in C#, since MainWindowTitle is read-only. But then I found the following API method:
[DllImportAttribute("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetConsoleTitle(IntPtr lpConsoleTitle);
In this case I can easily set the window title; either by passing it as parameter along with ProcessStartInfo , or simply generating it within the console itself.
Thanks for thought-provoking impulse.
Cheers,
Roland
|
|
|
|
|
If your GUI app crashes, I see no way for it to even try to do this beforehand.
Are you also developing the console apps? If so, maybe the console app can monitor the existence of the GUI app and hide and reshow itself on its own?
|
|
|
|
|
Yes, we create both, the GUI and the Console Apps. The latter one can be executed manually or started through the UI (invisible).
So we are actually realy monitoring the UI, but had no (good) idea how to make the console show itself when the GUI was gone.
But as a result of Alan's thought-provoking impulse I have an idea how to do this now.
Cheers, Roland
|
|
|
|
|