0

I'm trying various options of creating a BHO for traversing HTML page DOM. One implementation uses C# and it's registered in registry with ApartmentModel set to Both. It goes like this:

  1. retrieve IWebBrowser2.Document
  2. obtain IDocumentSelector interface from document object
  3. invoke IDocumentSelector.querySelectorAll("*") which yields a IHTMLDOMChildrenCollection reference
  4. get IHTMLDOMChildrenCollection.length
  5. run the for-loop in 0..length range (for(int index = 0; index < totalCount; index++)),
  6. inside loop iteration obtain each collection item using IHTMLDOMChildrenCollection.item(),
  7. cast the collection item reference to IHTMLElement2,
  8. obtain IHTMLElement2.getClientBoundingRect()

and it works rather fine, a page with about 1500 elements gets traversed in 200-300 milliseconds (loop duration is measured by reading DateTime.UtcNow before and after the loop and getting TotalMilliseconds from the readings difference).

Another implementation in done with Visual C++ and ATL. It does mostly the same as the C# version. CComQIPtr is used in place of casts. The loop is the same. It's also registered with ApartmentModel set to Both.

The C++ implementation traverses the very same page DOM in 40-60 milliseconds. Time is measured by reading GetTickCount() before and after the loop and getting the difference.

Then I exclude the step 8 from inside loop iteration - item is obtained and IHTMLElement2 is obtained from it but getClientBoundingRect() is not invoked. After this change both implementations run in mostly the same time - 40-50 milliseconds.

This looks weird. Why would only getClientBoundingRect() be affected? What's so special in it that it slows down so much?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • 1
    First, I'll just say benchmarking correctly is tough. I always use a `Stopwatch`, not `DateTime.UtcNow` and you need to run multiple iterations. The first time through, lazy loading is taking place for C# and is generally much slower than subsequent iterations. That being said, we're not going to be able to tell you why one is slower than the other without seeing the actual code for both. For example, saying "run the for-loop in 0..length range" could mean several things, some of which would be slower than others. – itsme86 Sep 30 '20 at 15:24
  • @itsme86 I clarified how the loop header is organized. – sharptooth Sep 30 '20 at 15:28
  • @itsme86 The results are mostly the same with `Stopwatch`. – sharptooth Sep 30 '20 at 15:33
  • Do you have a reproducing sample (with html in question)? – Simon Mourier Sep 30 '20 at 16:21
  • Can you please inform us, which version of the IE browser you are using for making this test? On which OS build you are producing this issue? If possible, you can you share both C# and C++ code example? We can try to test the issue and check for the issue. – Deepak-MSFT Oct 01 '20 at 02:50
  • @SimonMourier No, I cannot invest time in producing a minimal working sample of a BHO before I know that the thing possibly works with reasonable performance. – sharptooth Oct 01 '20 at 09:42
  • Is, in general, pure C/C++ COM call faster than C# COM call? Yes, for example https://pastebin.com/raw/kWirNfXN (.NET framework) but there's not only the call itself, there can be everything that's around (like parameters, allocations, etc.). That wouldn't necessarily explain a 5x faster, but that possible. As soon as you start doing other things (connecting to internet, database, whatever) these pure numbers (~6M calls per second in C#) may become insignificant, depends on context. Difficult to say w/o some reproducing code. – Simon Mourier Oct 01 '20 at 11:36

0 Answers0