.NET Forum / .NET Framework / Interop / September 2005
VSS Interop in C# terrible compared to C++ (v1.1)
|
|
Thread rating:  |
Stu Carnie - 09 Sep 2005 06:33 GMT All performance tests were from v1.1 of the framework.
I have read numerous articles on performance and tuning, however I am still perplexed (and a little concerned) with the performance differences in the following scenario.
Scenario:
C# Console app which uses the Microsoft.VisualStudio.SourceSafe.Interop primary interop assembly.
C# console app does the following:
1. Constructs an IVSSDatabase object.
2. Connects to my VSS database running on a server machine on the same local network (IVSSDatabase.Open)
3. Calls the IVSSDatabase.get_Item method, specifying an absolute path in my VSS db. Returns IVSSItem.
4. Calls the IVSSItem.get_Items to retrieve an IVSSItems collection.
5. Recursively iterates over this collection, writing out the Name (IVSSItem.Name) and checking the Type for VSSITEMTYPE_PROJECT, so it can iterate over that IVSSItem's children.
We are accessing three members of the IVSSItem interface: Method Returns ---------------------------- get_Items : IVSSItems (IEnumerable) Name : System.String Type : System.Int32
1 member of the IVSSItems interface: Method Returns ---------------------------- get_Item : IVSSItem
Results (all release builds, outside debugger):
1. C# - The code traverses about 850 IVSSItem objects - not that many - and takes 16 seconds to complete.
2a. Native C++, traverses the same 850 IVSSItem objects in 2 seconds. For all intents and purposes, the code is line for line identical.
2b. Compile with the /clr, and we're up to 16 seconds again (interfaces are declared in a header file, natively, not using interop assembly).
2c. Compile with the /clr, and wrap the main and processchildren functions in #pragma unmanaged, and still 16 seconds.
3. Comment out the printing of the Name and still takes 16 seconds. (no more marshalling of System.String)
I can't post specifics about v2.0, but lets say I wouldn't be posting if it was a significant improvement.
What are my options? Any suggestions?
Cheers,
Stuart
Stu Carnie - 09 Sep 2005 06:37 GMT ...and I also tried manually creating the interop assembly using tlbimp /unsafe, but still 16 seconds.
Robert Jordan - 09 Sep 2005 23:21 GMT Hi Stu,
> I have read numerous articles on performance and tuning, however I am > still perplexed (and a little concerned) with the performance [quoted text clipped - 54 lines] > > What are my options? Any suggestions? VSS is terrible slow. Even the 2 seconds for 800 items of the native version are scarry.
You may speed up the interop with an unmanaged COM object as a wrapper between VSS and your managed app. The wrapper must have a less chatty interface. For example, the wrapper might iterate over the item collection and return an array to the managed app. 850 get_Item interop calls were reduced to one call, consuming much more RAM, of course.
Cheap, fast, good. Pick two ;-)
Rob
Robert Jordan - 10 Sep 2005 16:20 GMT > VSS is terrible slow. Even the 2 seconds for 800 items of the native > version are scarry. I must correct myself! With a small C# app I was able to enum about 3000 items per second. I guess something is wrong with your VSS setup.
bye Rob
Stu Carnie - 11 Sep 2005 00:08 GMT Was your VSS database local?
The VSS db is running on a network server (dedicated). Is there any possibility the runtime is checking file accesses across the wire and slowing things down?
I also have many projects under this tree (not 850 files in 1 project), so the code calls get_items (the child collection) numerous times.
e.g.
path1
|_path1.1 | |_path1.1.1 | | | |_path1.1.1.1 | |-file-1 | : | |-file-n | |_path1.1.2 | | | |_path1.1.2.1 | | |-file-1 | | : | | |-file-n | | | |_path1.1.2.2 | |-file-1 | : | |-file-n | | |_path1.1.3 |-file-1 : |-file-n
You get the picture. There are a lot of vss projects ('paths') to iterate over and are several levels deep..
Cheers,
Stu
Robert Jordan - 11 Sep 2005 02:03 GMT Hi Stu,
> Was your VSS database local? No. On a non-dedicated Unix server in the same 100Mbit LAN segment. The DB contains 30K files.
The only difference we might have: on my development machine I have a VSS client version that was delivered with VS.NET 2005. But I never felt any speed difference compared to VSS 6.0, so it's probably unlikely to be the reason.
> I also have many projects under this tree (not 850 files in 1 project), > so the code calls get_items (the child collection) numerous times. Me too.
Here is my C# test. The interop assembly was generated with:
tlbimp /out:Interop.VSS.dll /namespace:Microsoft.SourceSafe "c:\Program Files\Microsoft Visual SourceSafe\ssapi.dll"
and the command line application with:
csc -r:Interop.VSS.dll vssdir.cs
// vssdir.cs using System; using Microsoft.SourceSafe;
class VssDir { static VSSDatabase db;
static void Main (string[] args) { if (args.Length < 3) { Console.Error.WriteLine ("usage: vssdir path-to-srcsafe.ini username passwd"); Environment.Exit (1); }
try { db = new VSSDatabase (); db.Open (args [0], args [1], args [2]);
EnumItem (db.get_VSSItem("$/", false), 0);
db.Close (); } catch (Exception ex) { Console.Error.WriteLine (ex.Message); } }
static void EnumItem (IVSSItem item, int level) { Console.WriteLine ("{0}{1}", new String (' ', level), item.Name); if (item.Type == 0) { foreach (IVSSItem i in item.get_Items (false)) { EnumItem (i, level + 1); } } }
}
Stu Carnie - 11 Sep 2005 05:03 GMT Thanks mate - looks very similar to my code - access all the same members.
I'll compile it and let you know..
. . . . . . . . It's running now, so grab your self a cuppa, while you wait :)
56 seconds for 16817 files - about 300 / sec. Quite a difference from your 3000 / sec (my dev box is a 3.0GHz HT P4 w/ 2GB RAM).
I am downloading the 2005 client for VSS now to see if that possibly makes a difference..
I'll let you know if a future post.
Thanks again for your input.
Cheers,
Stu
Stu Carnie - 11 Sep 2005 06:26 GMT So here is my CPP version for you to try:
* * * vssdircpp.cpp * * *
#include "comutil.h" #include "atlbase.h"
#include "stdio.h" #include <iostream> #include <fstream> #include <string>
using namespace std;
#import "c:\program files\Microsoft Visual SourceSafe\ssapi.dll" raw_interfaces_only no_namespace named_guids
int level = 0;
inline void TESTHR(HRESULT x) {if FAILED(x) { IErrorInfo *__pIE; GetErrorInfo(0, &__pIE); throw _com_error(x, __pIE);} };
void processchildren(IVSSItemPtr item) { level++;
IVSSItemsPtr children; TESTHR(item->get_Items(VARIANT_FALSE, &children));
long items; TESTHR(children->get_Count(&items));
IVSSItemPtr child; for (int i = 1; i <= items; i++) { TESTHR(children->get_Item(_variant_t(i), &child));
_bstr_t name; TESTHR(child->get_Name(name.GetAddress())); cout << string(level, ' ') << (LPTSTR)name << endl;
int type; TESTHR(child->get_Type(&type)); if ((VSSItemType)type == VSSITEM_PROJECT) { processchildren(child); } } level--; }
int main(int argc, char* argv[], char* envp[]) {
if (argc < 2) { cerr << "Usage: " << argv[0] << " <path-to-srcsafe.ini>" << endl; return 1; }
CoInitialize(NULL);
CComBSTR srcsafeINI(argv[1]);
try { CComPtr<IVSSDatabase> vssDB2; TESTHR(vssDB2.CoCreateInstance(CLSID_VSSDatabase));
TESTHR(vssDB2->Open(srcsafeINI, NULL, NULL));
IVSSItemPtr item; TESTHR(vssDB2->get_VSSItem(CComBSTR(L"$/"), VARIANT_FALSE, &item));
processchildren(item); } catch (_com_error &e) { _bstr_t errMsg = e.Description(); cerr << _T("** ERROR from Source Safe : ");
if (errMsg.length() > 0) { cerr << (wchar_t*)errMsg << endl; } }
return 0; }
1. Start up a VS 2003 Command Prompt 2. compile: cl /EHsc /O2 /MD vssdircpp.cpp
Took 6.686 seconds (as opposed to 56) so 2541 files / sec, which is closer to your managed version!
I also compiled with the /clr switch as follows cl /EHa /O2 /MD /clr vssdircpp.cpp
6.5 seconds for the managed C++ 2003 version. Using reflector, I can confirm it's all managed code.
However, the same C++ code above compiled for .Net v2.0 yields poor results - little difference to the 2003 C# version. I'm going to raise this as a bug...
Cheers,
Stu
Stu Carnie - 11 Sep 2005 08:01 GMT Bug ID: FDBK36539
FWIW, the perf numbers are there..
Stu Carnie - 11 Sep 2005 08:53 GMT Alright! Found the problem with /CLR for 2005 and C# for 2003...
Firstly for C#, the lack of [STAThread] against the entry point "main" allows the CLR to choose the apartment model for any interop, and it is defaulting to MTA!! I added [STAThread] and now my C# app runs as fast as the managed and unmanaged C++ versions! Yeah!
Now, I guess in 2003, it defaulted to [STAThread] when compiling C++ with the /clr option, whereas for 2005 it's defaulting to allowing the CLR to choose, which also defaults to MTA.. So, I changed my compiler options for the 2005 build to:
cl /EHs /O2 /clr vssdircpp.cpp /link /CLRTHREADATTRIBUTE:STA
Cheers,
Stu
Robert Jordan - 11 Sep 2005 13:44 GMT Hi Stu,
> Alright! Found the problem with /CLR for 2005 and C# for 2003... > > Firstly for C#, the lack of [STAThread] against the entry point "main" > allows the CLR to choose the apartment model for any interop, and it is > defaulting to MTA!! I added [STAThread] and now my C# app runs as fast > as the managed and unmanaged C++ versions! Yeah! Jesus! I my sample I skipped the STAThread-attribute while reformating the code for the mail.
Nice to hear that it works now.
Rob
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|