Tuesday, December 30, 2008

International Internet censorship

I've just read that the government of UK is contacting the government of US to create an international Internet censorship system. I was really happy when I read it first. I read the whole article after that and I wasn't happy at all.
They want to create a classification system for all the sites and make the ISPs to force the classification and remove 'improper' sites and pages.

I was happy because I think there should be a strong control over the pages kids can access. There should be strong control over pages that contain illegal content. But these should be categorized by an independent judge considering laws, not a group of people with morale influences.

Let's take the most recent case with Facebook.com. They don't allow images about moms breastfeeding their babies. It's OK from their point of view and they own the web application. On the other hand there is no law against such images and there are laws in many states of the US that moms can breast-feed babies in public places. It's their choice. Imagine that some group of people in an 'Internet Censorship Board' would take the same step.

I would be happy with a system that would build up as follows:

  • Sites should rate themselves (or by something like the Certificate Authorities)
  • Intentional misratings should be punished somehow (by the law, blacklisting or something like that if it's needed)
  • There should be applications built into the browsers or standalone versions that can filter content by these ratings

If you look at popular sites dealing with sexuality they usually mark themselves somehow. A standard is missing and I think it should be an open standard.

Thursday, December 25, 2008

Silverlight authentication

Illustration: security If you need to access server resources from Silverlight (e.g uploading statistics, reading data from database), the easiest solution is to invoke an XML Web Service. I've seen many examples of Silverlight authentication for Web Services. Many of them are illustrated and well-written. The main problem is the security: they create the illusion of security. So if you want to create a secure authentication method, you can use the following solution to achieve a good level of security.

Log in user (either using ASP.NET or using Silverlight through an XML  Web Service).

  1: public bool Authenticate(string Username, string Password)
  2: {
  3:     if (FormsAuthentication.Authenticate(Username, Password))
  4:     {
  5:         FormsAuthentication.SetAuthCookie(Username, false);
  6:         return true;
  7:     }
  8:     return false;
  9: }

Now you can check if the user is authenticated.

  1: if (HttpContext.Current.User.Identity.IsAuthenticated)  
  2: {  
  3:     DoWork();
  4:     return true;  
  5: }  
  6: else  
  7: {  
  8:     DoNothingUserNotAuthenticated();
  9:     return false;  
 10: }  

Now there are two main security threats:

  • Login is insecure
  • HttpContext function is insecure

Login is insecure

You have to implement login functionality securely to make you application secure. So use SSL to prevent eavesdropping  and tempering login data.

HttpContext is insecure

ASP.NET Forms authentication uses cookies to identify users (by default). You have to encrypt the authentication ticket using the server key and decrypt that whenever you read that. Don't persist the cookie if you don't have to.

Security

The solution above can be secure. You can log on to the site. A security ticket is created with the user credentials, encrypted and stored on the user's machine. This cookie is accessible whenever user have to prove his identity, so you can access it even in an XML Web Service or through HttpContext.

Direct authentication pattern (I think) is not a solution for Silverlight Web Services, because password goes as plain text to the service every time it is invoked, or severe performance degradation occurs.

Tuesday, December 16, 2008

Visual Studio 2010

.NET Logo Microsoft has announced Visual Studio 2010 (VS). The list of changes that sounds interesting to me:

  • The user interface will be implemented in Windows Presentation Foundation (WPF)
  • Managed addins will be supported
  • Multiple new windows
  • Built-in Test Driven Development (TDD) support
  • Built-in ASP.NET Model-View-Control (MVC) support
  • JQuery will be part of VS
  • Built-in Silverlight 2 support
  • Native Windows 7 support (means C++, MFC)
  • Multiple new UML-like diagrams (Team System (VSTS): use case, activity, sequence)
  • New Architecture Explorer (VSTS)
  • New Architecture Layer Diagram (VSTS)
  • Built-in support for Windows Azure cloud computing environment
  • Built-in support for Parallel development (Parallel Extensions, native, managed)

I can see two main possible problems with VS 2010. The first is WPF UI, the second are managed addons. Both means significant performance degradation. One of the main goals of Windows 7 is significantly improved performance. All the performance we can save on Windows 7 will be lost on WPF. VS 2008 is one of the fastest IDEs on the market, but it's becoming more and more slower. I doubt its performance will be as good as current VS 2008 performance.

On the other hand, I can hardly wait for built-in Silverlight 2, JQuery, Parallel Extension and MVC support. These will be great changes.

Link: Visual Studio 2010 Overview
Link: Visual Studio 2010 Product Overview (PDF)
Link: Visual Studio 2010 CTP Download

Saturday, December 13, 2008

Model checking with SAL

SAL stands for Symbolic Analysis Laboratory. A document from SRI International defines it the following way:

The Symbolic Analysis Laboratory (SAL) is a set of tools for the specification, exploration, and verification
of state-transition systems. SAL includes symbolic model-checking tools based on solvers and
decision procedures for linear arithmetic, uninterpreted functions, and propositional logic, among others.
This enables the analysis of a variety of infinite-state systems. In particular, SAL can be used to model
and verify timed systems, which combine real-valued and discrete state variables.

Firstly SAL defines a context. You can define data types and modules in that. Modules encapsulate variables and transitions. Transitions manipulate variables. 

The main goal is to define modules that implement the functionality of the model. When you have defined the model in SAL, you have to define theorems to prove them. It is usually implemented in Linear Temporal Logic (LTL).  There are four basic LTL expressions:

  • Fp - p will be valid in a future state
  • Gp - p globally valid
  • Xp - p will be valid in the next state
  • p U q - p will be valid in every single state until p becomes valid

Context

ContextName : CONTEXT =
BEGIN
  ...
END

The ContextName and the filename must be the same.

Module

ModuleName : module =
BEGIN
  variables
  initialization
  TRANSITION expressions
  ...
END;

You can execute modules synchronously by chaining them:

main : MODULE = 
        module1 || module2 || ... ||  moduleN;

Decisions in transitions can be defined easily with brackets:

TRANSITION
[
  condition1 -->
    expression1;
    expression2;
[]
  condition2 --> expression
[]
  ELSE -->
]

If condition is true, branch will be executed and transition processing stops. The final ELSE --> is needed to prevent deadlocks.

An example for a module (it's inside a context):

Phases : type = {p1, p2,p3};

Phase : MODULE =
BEGIN
  INPUT tick : BOOLEAN
  OUTPUT WorkPhase : Phases

  INITIALIZATION tick = false;
  INITIALIZATION WorkPhase = p1;

  TRANSITION
  [
    tick = true AND WorkPhase = p1 --> WorkPhase' = p2;
  []
    tick = true AND WorkPhase = p2 --> WorkPhase' = p3;
  []
    tick = true AND WorkPhase = p3 --> WorkPhase' = p1;
  []
    ELSE -->
  ]
END;

The VariableName' = NewValue is the value setting syntax.

The theorem can be expressed like this:

TheoremName : THEOREM ModuleName |- LTLExpressions

An example for theorem:
Gas : THEOREM main |- G(GasCount > 0 => F(GasPrice =2));

Friday, December 5, 2008

OpenGL solid cone without glut

The following function draws a solid sphere in OpenGL without glut.

  1: void solidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks)
  2: {
  3:   glBegin(GL_LINE_LOOP);
  4:   GLUquadricObj* quadric = gluNewQuadric();
  5:   gluQuadricDrawStyle(quadric, GLU_FILL);
  6: 
  7:   gluCylinder(quadric, base, 0, height, slices, stacks);
  8: 
  9:   gluDeleteQuadric(quadric);
 10:   glEnd();
 11: }
It creates a line loop at line 3. It crates a quadratic object after that (line 4) and sets drawing mode to fill the gaps (line 4, 5).  It calls the gluCylinder() function (line 7). The base radius will be the cone radius. The top radius will be 0 to achieve a cone shape. Finally it deletes the quadratic object (line 9). The result is same as calling glutSolidCone() with the same arguments.

OpenGL solid sphere without glut

The following function draws a solid sphere in OpenGL without glut.

  1: void solidSphere(GLdouble radius, GLint slices, GLint stacks)
  2: {
  3:   glBegin(GL_LINE_LOOP);
  4:   GLUquadricObj* quadric = gluNewQuadric();
  5: 
  6:   gluQuadricDrawStyle(quadric, GLU_FILL);
  7:   gluSphere(quadric, radius, slices, stacks);
  8: 
  9:   gluDeleteQuadric(quadric);
 10:   glEnd();
 11: 
 12: }
It creates a line loop at line 3. It crates a quadratic object after that (line 4) and sets drawing mode to fill the gaps (line 4).  It draws a sphere using the previously created quadratic object passing the parameters to the function (line 7). Finally it deletes the quadratic object (line 9). The result is same as calling glutSolidSphere() with the same arguments.

Wednesday, December 3, 2008

FormsAuthenticationTicket UserData disappears

I'm building an ASP.NET site and I had to implement the authentication/authorization subsystem. This is a standard code that is recommended by MSDN and several tutorials on the Web:

  1: if (loginResult == LoginResult.Successful)
  2: {
  3:   if(Request.QueryString["ReturnUrl"] != null)
  4:   {
  5:     Security.CreateAuthCookie ( this, txtUserName.Text );
  6:     FormsAuthentication.RedirectFromLoginPage ( txtUserName.Text, chkRememberMe.Checked );
  7:   }
  8:   else
  9:   {
 10:     Security.CreateAuthCookie ( this, txtUserName.Text );
 11:   }
 12: }

If username and password is correct, user can log in. If there is a return URL (this means he tries to access secured content), we have to create an authentication cookie and redirect user to that URL.  Security class and LoginResult enumerations are own implementations.

The code above will not work correctly if you are using own FormsAuthenticationTicket. Internet Explorer seems to work fine, but Firefox keeps showing the Login page. It seems there is a bug in the Framework and the UserData property (where we store e.g. roles) of the ticket will be empty (sometimes). The solution for the problem is changing line 6:

Response.Redirect( FormsAuthentication.GetRedirectUrl( this.txtUserName.Text.Trim(), false ));

Article Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication on MSDN is correct, use that for implementing own Forms authentication.

Sunday, November 23, 2008

C# 4.0 - Overcomplicated?

I've seen C# 4.0 draft and something came into my mind: is this language as simple as Microsoft used to advertise it? Let me show a few C# 4.0 features.

New C# 4.0 features

Dynamic types

  1: dynamic d = GetDynamicObject(…);
  2: d.M(7); // calling methods
  3: d.f = d.P; // getting and settings fields and properties
  4: d[“one”] = d[“two”]; // getting and setting thorugh indexers
  5: int i = d + 3; // calling operators
  6: string s = d(5,7); // invoking as a delegate

C# used to be a static language. Now you can create dynamic types as well.

Optional parameters

  1: public void M(int x, int y = 5, int z = 7){...};

x is mandatory. y and z are optional parameters.

Named parameters

  1: M(z: 3, x: 1);

COM interop

You have to set a cell in Excel now as follows:

  1: ((Excel.Range)excel.Cells[1, 1]).Value2 = "Hello";

In C# 4.0 you can do this thanks to dynamic types:

  1: excel.Cells[1, 1].Value = "Hello";

The need for language improvements

If you look at C# improvements like generics, var, anonymous methods, dynamics etc., we can see big needs behind them. The main reasons are LINQ and COM interoperability improvements. If you know these 'extensions', you can imagine the complexity of LINQ without e.g. var.

Implications

Can you remember Perl? It used to be a very promising (scripting) language. You can code/talk Perl on very different levels (I love Perl for this :)). If you don't know that specific level (expressions), you can hardly read/write that code. An example:

  1: print "Hello, world!\n";

or

  1: say 'Hello, world!'

Does C# walks the same path? Introducing dynamic types to a basically static language, introducing optional and named parameters to a C(++)-like language. I love changes, but these can generate problems.

You can't use e.g. generics at certain companies because some programmers don't understand them (maybe it's not the best example but I hope you can get my idea).

Can you or do you read/write all the following C# 3.5 features?

  • implicitly typed local variables
    var myInt = 0;
  • automatic properties
    class Car
    {
       public string PetName { get; set; }
    }
  • extension methods
    static class MyExtensions
    {
      public static void DisplayDefiningAssembly(this object obj)
      {
      Console.WriteLine("{0} lives here:\n\t->{1}\n", obj.GetType().Name, Assembly.GetAssembly(obj.GetType()));
      }
    }
  • lambda expressions
    Increase lambdaDelegate = value => value * 2;
    Console.WriteLine(string.Format("Lambda expression: {0}", lambdaDelegate(5)));

I think you don't have to use all of them or even read all of them. Unfortunately I'm sure that a lot of developers can't even read many of them.

Wednesday, November 19, 2008

DB optimization

Someone asked me to help him optimize a SQL operation. He said he is using SQLite database but his query is very slow. He tried indices as well, but it takes 1 hour to insert 20 users into his database. It's just 1 minute to insert 7 users without indices. Finally he sent me a query that runs awfully slow (for hours):

SELECT SUM(size) AS s FROM (SELECT DISTINCT hash, size FROM files);

Indices

If you define an index on a column, it takes time to maintain it. In this case it took a lot of time to insert new data into the index structure (usually something like a B* tree). He had to insert hundreds of users in one batch. It can worth disabling or deleting indexes before inserting such an amount of new records once. You can recreate or regenerate the indices after running the whole batch.

DISTINCT

The SQL query above ran very slow because of the DISTINCT keyword. I advised to try it without DISTINCT and the query ran very fast.

Conclusion

Keep in mind that indices can make insert operations very slow and projections and joins can make a select very slow. It worths to measure performance and use real usage statistics to tune your database and queries.

Tuesday, November 18, 2008

Silverlight 2 Designer crash

Visual Studio 2008 crashed every time I opened a XAML file. No crash dump, no messages, VS just disappeared. I used Silverlight designer before and worked fine. One day it just started crashing.

I've removed everyting from my computer containing Silverlight in it's name. I ran Microsoft Silverlight Tools Beta 2 for Visual Studio 2008 after that. Silverlight 2 content appeared in my browser, but Visual Studio 2008 keeped crashing. I reran Visual Studio 2008 SP1 setup. It didn't help.

Finally I tried Microsoft® Silverlight™ Tools for Visual Studio 2008 SP1. It works. XAML designer works, Visual Studio 2008 doesn't crash!!! It seems Silverlight chainer doesn't contain SP1 tools. So don't forget to install it manually if you have similar problems.

Friday, May 23, 2008

IIS debugging macro

Usually developers use a single remote server while developing custom SharePoint solution. It means the developer tools and the server are not on the same machine. You can connect to the server after starting the Visual Studio Remote Debugger. Now you can attach debugger to the remote w3wp.exe processes. This process can be very annoying after a while.
It is a macro that will automate this process:
   1:  Imports System
   2:  Imports EnvDTE80
   3:  Imports System.Diagnostics
   4:   
   5:  Public Module AttachToWebServer
   6:   
   7:      Public Sub AttachToWebServer()
   8:   
   9:          Dim AspNetWp As String = "aspnet_wp.exe"
  10:          Dim W3WP As String = "w3wp.exe"
  11:   
  12:          If Not (AttachToProcess(AspNetWp)) Then
  13:              If Not AttachToProcess(W3WP) Then
  14:                  System.Windows.Forms.MessageBox.Show(String.Format("Process {0} or {1} Cannot Be Found", AspNetWp, W3WP), "Attach To Web Server Macro")
  15:              End If
  16:          End If
  17:   
  18:      End Sub
  19:   
  20:      Public Function AttachToProcess(ByVal ProcessName As String) As Boolean
  21:   
  22:          Dim dbg2 As EnvDTE80.Debugger2 = DTE.Debugger
  23:          Dim trans As EnvDTE80.Transport = dbg2.Transports.Item("Default")
  24:   
  25:          Dim Processes As EnvDTE.Processes = dbg2.GetProcesses(trans, "DOMAIN\USER@MACHINE")
  26:          Dim Process As EnvDTE.Process
  27:          Dim ProcessFound As Boolean = False
  28:   
  29:          For Each Process In Processes
  30:              If (Process.Name.Substring(Process.Name.LastIndexOf("\") + 1) = ProcessName) Then
  31:                  Process.Attach()
  32:                  ProcessFound = True
  33:              End If
  34:          Next
  35:   
  36:          AttachToProcess = ProcessFound
  37:   
  38:      End Function
  39:   
  40:  End Module

Change the "DOMAIN\USER@MACHINE" to your own ID. The DOMAIN\USER is the debugger user, the MACHINE is the debugging target machine. You can get this ID from Visual Studio Remote Debugger first log line or from a previous connection log line.

This macro is based on Howard van Rooijen macro implementation.


Localhost debugging: change DOMAIN\USER@MACHINE to empty string ("").

Developer (Visual Studio-integrated) server debugging: add WebDev.WebServer.EXE before If Not (AttachToProcess(AspNetWp)) Then like If Not (AttachToProcess("WebDev.WebServer.EXE")) Then

Link: View and download the script on Google Code [.vb]
Link: Attach to Web Server Macro for Visual Studio

Wednesday, May 21, 2008

Change ASP.NET User Control UICulture

Illlustration: language Sometimes you have to change the culture settings of a user control in runtime. Let's say we have to change the language of a login form on user click. Let's say we do not want to and cannot change the culture of the page (e.g.  the user control is embedded in a SharePoint page).

The first step is to create a Local Resource for the user control (.resx). Now it's possible to change the language dynamically.

The next step is to put buttons on the form and create event handlers for each languages. The standard code to change the culture is something like this:

System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("hu-HU");

Unfortunately we will not be successful this way.

The solution is to override the FrameworkInitialize() method and set the Thread.CurrentThread.CurrentUICulture inside that.

You will probably have to use Session state to store the current language. If we set the Session variable in an event handler, we will have to click twice on the button to change the language of the form. The trick is  the following:

Server.Transfer(Request.Url.PathAndQuery, false);

Now the user control will appear with the selected culture settings after pressing the button.

Tuesday, January 15, 2008

Microsoft Parallel Extensions

I've installed Microsoft Parallel Extension 1.0.2873.22603 on my machine recently. I want to try its capabilities, so I've created a small test application.

In general, there are different levels of parallelism: instruction, task, etc. In the example below, I'll try iteration parallelism (a kind of imperative operation parallelism). The .NET Framework should automatically divide the work to run on multicore and multiprocessor systems.

The example

The main idea behind the example is iterating in a nested for loop. The inner loop will increase an integer variable. It will generate processor load and it will take a while to compute the result. The application with basic settings will generate 10,000,000,000 (100,000*100,000) loops.

My machine runs a Windows XP operating system with Physical Address Extension, runs on Intel Core2 CPU T7200 @2.00 GHz and has 1 GB of RAM.

The source

using System;
using System.Threading;

namespace PFXTest1
{
    class Program
    {
        /// <summary>
        /// Iteration start number
        /// </summary>
        const int from = 0;
        /// <summary>
        /// Iteration end number
        /// </summary>
        const int to = 100000;
        /// <summary>
        /// Progress bar scaling
        /// </summary>
        const int progressbar = to / 40;

        /// <summary>
        /// Show progress bar
        /// </summary>
        const bool progress = true;

        /// <summary>
        /// Task start time
        /// </summary>
        static DateTime timerStart;
        /// <summary>
        /// Task finish time
        /// </summary>
        static DateTime timerFinish;
        
        /// <summary>
        /// Main function
        /// </summary>
        /// <param name="args">Application args</param>
        static void Main(string[] args)
        {
            Console.WriteLine("PARALLEL LIBRARY (PFX) TEST");
            Console.WriteLine("Artur Herczeg, http://techies.teamlupus.hu");
            Console.WriteLine();
            
            NormalRun();
            ParallelRunInner();
            ParallelRunOuter();
            ParallelRunBoth();

            Console.ReadKey();
        }

        /// <summary>
        /// Non-parallel code
        /// </summary>
        private static void NormalRun()
        {
            if (progress)
            {
                Console.Write("Normal progress:         [");
                int oldcursor = Console.CursorLeft;
                Console.CursorLeft += to / progressbar;
                Console.Write("]");
                Console.CursorLeft = oldcursor;
            }

            timerStart = DateTime.Now;

            int count = int.MinValue;
            for (int i = from; i < to; i++)
            {
                for (int j = from; j < to; j++)
                {
                    count++;
                }

                if (progress && i % progressbar == 0)
                {
                    Console.Write("=");
                }
            }

            timerFinish = DateTime.Now;

            if (progress)
            {
                Console.WriteLine("]");
            }
            Console.WriteLine("Normal runtime: {0}", timerFinish - timerStart);
        }

        /// <summary>
        /// Inner and outer for loops are both parallel
        /// </summary>
        private static void ParallelRunBoth()
        {
            if (progress)
            {
                Console.Write("Parallel both progress:  [");
                int oldcursor = Console.CursorLeft;
                Console.CursorLeft += to / progressbar;
                Console.Write("]");
                Console.CursorLeft = oldcursor;
            }

            timerStart = DateTime.Now;

            int count = int.MinValue;
            Parallel.For(from, to, i =>
            {
                Parallel.For(from, to, j =>
                {
                    count++;
                });

                if (progress && i % progressbar == 0)
                {
                    Console.Write("=");
                }
            });

            timerFinish = DateTime.Now;

            if (progress)
            {
                Console.WriteLine("]");
            }
            Console.WriteLine("Parallel both runtime: {0}", timerFinish - timerStart);
        }

        /// <summary>
        /// Outer for loop is parallel
        /// </summary>
        private static void ParallelRunOuter()
        {
            if (progress)
            {
                Console.Write("Parallel outer progress: [");
                int oldcursor = Console.CursorLeft;
                Console.CursorLeft += to / progressbar;
                Console.Write("]");
                Console.CursorLeft = oldcursor;
            }

            timerStart = DateTime.Now;

            int count = int.MinValue;
            Parallel.For(from, to, i =>
            {
                for (int j = from; j < to; j++)
                {
                    count++;
                }

                if (progress && i % progressbar == 0)
                {
                    Console.Write("=");
                }
            });

            timerFinish = DateTime.Now;

            if (progress)
            {
                Console.WriteLine("]");
            }
            Console.WriteLine("Parallel outer runtime: {0}", timerFinish - timerStart);
        }

        /// <summary>
        /// Inner for loop is parallel
        /// </summary>
        private static void ParallelRunInner()
        {
            if (progress)
            {
                Console.Write("Parallel inner progress: [");
                int oldcursor = Console.CursorLeft;
                Console.CursorLeft += to / progressbar;
                Console.Write("]");
                Console.CursorLeft = oldcursor;
            }

            timerStart = DateTime.Now;

            int count = int.MinValue;
            for (int i = from; i < to; i++)
            {
                Parallel.For(from, to, j =>
                {
                    count++;
                });

                if (progress && i % progressbar == 0)
                {
                    Console.Write("=");
                }
            }

            timerFinish = DateTime.Now;

            if (progress)
            {
                Console.WriteLine("]");
            }
            Console.WriteLine("Parallel inner runtime: {0}", timerFinish - timerStart);
        }
    }
}

The results

PARALLEL LIBRARY (PFX) TEST
Artur Herczeg, http://techies.teamlupus.hu

Normal progress:         [========================================]
Normal runtime: 00:00:38.1875000
Parallel inner progress: [========================================]
Parallel inner runtime: 00:04:20.3125000
Parallel outer progress: [========================================]
Parallel outer runtime: 00:00:16.2187500
Parallel both progress:  [========================================]
Parallel both runtime: 00:05:12.2187500

Chart: Parallel.For performance

First impressions

There is just one way we can improve code execution speed. We can get better performance only with outer for parallelism. In this case, the inner loop can run on different processors - in my case, on different core. The parallel code runs twice faster than normal code because I've two cores.

If the inner for loop or both for loops are parallel, the code runs for 6-8 times longer. We can see here if we make a bad decision, parallel execution is much more worse than normal code execution.

Deeper look

I've recorded a performance monitor session on the test code.

CPU usage

See Parallel.For CPU usage graph.

The normal execution utilizes just one core, so the CPU utilization is 50%. The parallel inner and outer code takes up to 80%. The test code containing both inner and outer parallelism takes up 100% CPU time.

JIT

See Parallel.For JIT graph.

There is a huge JIT (Just-In-Time compile) activity when we start running a new parallel code. It's not surprising because native images are not generated for parallel assemblies (for System.Threading).

Classes and assemblies

See Parallel.For classes and assemblies graph.

Parallel functionality uses about 40 classes and two assemblies for runtime. No change in application domain number, so the parallel codes run in threads.

Threads

See Parallel.For thread graph.

The number of physical threads increase from 10 to 50 after starting parallel functions. This means the parallel optimizer considers the number of CPUs and the code, and chooses the possibly optimal thread number. It reminds me of the ThreadPool mechanism.

GC

See Parallel.For GC graph.

The sum of bytes in all heaps is about 2 MB after starting parallel code execution. This is almost zero in case of normal code.

Remoting

See Parallel.For remoting graph.

There is no remoting activity (there is just one application domain).

Marshalling

See Parallel.For marshalling graph.

There are regular native calls in parallel library. It will have its impact on portability (will it be possible?).