Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / September 2005

Tip: Looking for answers? Try searching our database.

VSS Interop in C# terrible compared to C++  (v1.1)

Thread view: 
Enable EMail Alerts  Start New Thread
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

Rate this thread:







Free Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.