Here is a little teaser program –
class Program {
#if DEBUG
static int test = 0;
#endif
static void Main(string[] args)
{
TestMethod(test);
}
[Conditional("DEBUG")]
static void TestMethod(int t) { }
}
Like all questions, should this compile or not? The thing to note here is the difference in behavior between the Conditional compilation attribute and a preprocessor directive. The answer is in the documentation of the conditional attribute class.
Applying ConditionalAttribute to a method indicates to compilers that a call to the method should not be compiled into Microsoft intermediate language (MSIL) unless the conditional compilation symbol that is associated with ConditionalAttribute is defined. Applying ConditionalAttribute to an attribute indicates that the attribute should not be emitted to metadata unless the conditional compilation symbol is defined. Any arguments passed to the method or attribute are still type-checked by the compiler.
UPDATE to my question in the community DL by Eric Lippert
>>So this in my understanding means that unlike a preprocessor directive, happens only during translation and that means type checking and parsing etc does happen even though the method is conditional in a sense and removed only at a later stage.
Correct. If you think about it a moment you’ll see why that has to work that way. Ask yourself a few questions about how this works:
Q: How does the compiler know to remove the method?
A: Because the method called has the conditional attribute on it.
Q: How does the compiler know that the method called has the conditional attribute on it?
A: Because overload resolution chose that method, and the metadata associated with that method has the attribute.
Q: How does the compiler know to choose that method?
A: By examining its arguments.
Therefore the arguments must be well-defined at the point of the call, even if the call is going to be removed. In fact, the call CANNOT be removed unless the arguments are there!
>>Could someone point me to which parts of the c# spec defines this behavior?
FYI, the specification begins with a handy “table of contents”, which is very useful for answering such questions. The table of contents of the specification states:
2.5.1 Conditional compilation symbols
17.4.2 The Conditional attribute
So my advice would be for you to look at sections 2.5.1 and 17.4.2 if you want the specification for conditional compilation symbols vs the conditional attribute.
Cheers,
Eric
I got to play (remotely) with one of these little boxes, few of the kicks you get out of being a perf dev. I fired up the taskbar just to see something totally mind blowing (atleast in the current times).
24-cores. Now isn’t that impressive :)
The “classic” classification problem has been around for quite while in Microsoft (and every where else) and this reference is something that you would hear quite often. You can find Nikhil Kothari’s post about Applying personas where he uses this analogy to describe types of programmers and another interesting post too http://www.codinghorror.com/blog/archives/001004.html. The intent here is not to describe this, those other links will help for that, but to call out how sometimes some features are buried deep in the guts of WCF. Well I maybe exaggerating a bit here. Anyway, one of the challenges of being a performance developer on this team is that I rarely get to deal with simplistic scenarios.
Now getting back to WCF. I have grown to admire it for its beauty of how the elements tie up so elegantly and the most scary part is that its elegance is what makes it so performant. Form follows function. One of the basic principles is that the runtime is fully async or so to speak tries to be fully async. This is primarily to avoid any type of blocking obviously. There is a the trade off when you want to make something async besides just the abysmal complexities of a series of Begins and Ends. You can end up in another critical problem, besides the overhead of a thread switch. This is the basic stack unwind time on the new thread and the overhead to enable this. What does that even mean?
Now think about putting a set of calls as follows on the same thread.
A => B => C => D => E (execute and return) Stack unwind id pretty straight forward right and you just need to trace back and POP. You have context/locals members. You name it and the calling method has it. So the call back just happens like
A <= B <= C <= D <= E (E is the starting point here)
So the call tree looks something like this
A
|—B
|—C
|—D
|—E
Well in an async call the issue is that it the initiating threads just ends its logical execution at E.
BeginA => BeginB => BeginC => BeginD => BeginE and returns
Sadly all other logical pieces of execution have to also stay in limbo till the inner begin invocation completes and that means that they have to stash their states onto something like an async result that the caller has to give back to them during execution resumption. So in short the AsyncResult is nothing but like a glorified stack pointer.
To duplicate what stack unwind does we end up creating a bunch of results that holds the data for execution and the callback path is a bit different on the thread and would be as follow.
EndA <= EndB <= EndC <= EndD <= EndE (thread starts here actally but logical execution is the reverse)
Here the call tree is not so simple. You have the initial one that looks like this.
BeginA
|—BeginB
|—BeginC
|—BeginD
|—BeginE
And when the end happens on the other completion thread as shown below.
EndE
|—EndD
|—EndC
|—EndB
|—EndA
Well so you end up paying double the stack unwind cost for an async call with the condition that you do incur a thread switch and true do go async. Note that this is not applicable to calls that complete synchronously cause they obey the regular unwind rules. Now if you are still wondering why go async at all then its time to hit the books cause we are waiting on “IO” and we if we hold on to a thread when we do IO its like buying a jumbo jet to get free peanuts. Again exaggeration. But the point is IO is way more expensive than a stack unwind so its better to free up our precious CPU cycles for other hungry requests.
Just as a conclusion. The async nature is not that simple to produce but has such returns for your investment that it just makes sense to go that route not only for frameworks like WCF but also other apps.
In my next post i’ll try to explain about a knob added in WCF, quite counter intuitive to basic understandings of async and IO and a part of WCF that’s not purely async per say. I was told by Wenlong to create this Elvis knob.
Update: Sept-05-09 - Concurrent receives.
Here is the knob that we added for enabling multiple receives
http://www.sajay.com/post/2009/08/03/Concurrent-Receives-MaxPendingReceive.aspx
Sometimes I have to fix certain issues in BizTalk and during one of these exercises I had to write a large message into the eventlog.OUCH! Ok now who does that ? Well I’m not at fault here but then again we did require this for some convoluted reason. Anyway there was some whacky boundary condition code. So to get a quick value just decided to flood my event log and see how much can it store.
static void Main(string[] args)
{
int limit=31000;
int source = 10; //212 is the limit here.
while(true)
{
try
{
SD.EventLog.WriteEntry(new string('s',source) , new string('v', limit), System.Diagnostics.EventLogEntryType.Information, 0, 0);
limit++;
}
catch (Win32Exception ex)
{
Console.WriteLine(--limit);
break;
}
}
SD.EventLog.WriteEntry(new string('s', source), new string('v', limit), System.Diagnostics.EventLogEntryType.Information, 0, 0);
Console.WriteLine("Total = " + (source + limit));
}
And guess – its a magic number 31884 and not 32k. System.Diagnostics.Eventlog actually uses advapi32!ReportEvent but this seems to have a 32k limit. Anyway short answer is that its not “exactly” 32k.
Its not technology but MAN!
I've been using Source Insight for a while now and wanted to add the Copy full path feature that vs 2008 has. Here is a small macro that does just that. Just create a AnyName.em file and add it to the project.
macro CopyFileFullpath()
{
hbuf = GetCurrentBuf()
if(hbuf == 0)
{
msg("No buffer available");
stop
}
hbufClip = GetBufHandle("Clipboard")
ClearBuf(hbufClip)
AppendBufLine(hbufClip, GetBufName(hbuf))
}
Note: If someone knows a better way do leave a feedback.
It was time and I decided to finally move, migrate and aggregate and also shoot myself in the foot. Any integration consultant knows that its one of the most painful and probably the most irritating jobs to do. But then again you are always so disconnected and have to update so many different systems. My case it was blogs.msdn.com, spaces.live.com and blogger.com. In short this was a mammoth task to get all my old stuff under one big umbrella which lead to the birth of this silly site. Now there is a technical aspect and an emotional aspect to this and this being my blog gives me the freedom to touch upon both finally.
Emotionally it was tiring and satisfying at the same time. The underlying engine was much more faster and it being just for blogging was pretty easy to understand. I used blogEngine.net primarily cause I don't understand much besides .net and due to some loyalty reasons which might not even be justified. Then again it was really simple to setup. Then again setting up is the first and only the first of the hurdles. The main problems were in setting it up right with the permissions so that the damn thing looks good and also works fine. I learned a few new tools and wrote a few also during this process. The end result of 24 hours of straight coding back breaking undisturbed hours with almost no food was honestly worth it cause after getting all the stuff I had been writing and putting them under one roof felt really good. I am happy that the old posts were where I left them and didn't take them down.
Finally as I decide its time to get back to work, I had one question. WFT were those people thinking when developed those systems. Don't they want it to work with any other system out there.. If they don't then idiots like me will have to rip it all apart and put a new system which won't be any different from what there is already. Freedom can be quite irritating at time especially when its someone else's (ouch! kidding) I'll get to the tooling and tricks I used to get this done. Its not pretty and I didn't intend it to be cause if more people suffer then something might be done.
Anyway the word ->
Its WORTH it.
I just had to put down this link for future reference.
To check for file permission you still have to try to openWrite it .
just check this out you still have to open and test it cause demand
only checks for CAS.. and well the code does have access to the
concept of the directory and the file .. but its NTFS that inhibits
this access.
using System;
using System.IO;
public class FileTest
{
public static void Main()
{
string fileName = @"c:\Security\text.txt";
System.Console.Write("test");
try
{
Console.WriteLine("File exists: " +
System.IO.File.Exists(fileName).ToString());
FileStream fs;
System.Security.Permissions.FileIOPermission f = new
System.Security.Permissions.FileIOPermission(System.Security.Permissions.FileIOPermissionAccess.AllAccess,
fileName);
f.Demand(); //Somehow i feel that this should have been enough..
Console.WriteLine("Demand checked");
if ((fs = System.IO.File.OpenRead(fileName)) != null)
{
fs.Close();
Console.WriteLine("File Closed");
}
}
catch (System.IO.IOException ex)
{
// Console.WriteLine(ex.StackTrace);
Console.WriteLine("Message " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}
}
<%@ Page CodeBehind="test.aspx.cs" Language="c#" AutoEventWireup="false" Inherits="SLK.RTS.Web.test" %>
<HTML>
<HEAD>
<script language="javascript">
function TabClick( nTab )
{ nTab = parseInt(nTab);
var oTab;
var prevTab = nTab-1;
var nextTab = nTab+1;
event.cancelBubble = true;
el = event.srcElement;
for (var i = 0; i < TabPage.length; i++)
{
oTab = Tab[i];
oTab.className = "clsTab";
oTab.style.borderLeftStyle = "";
oTab.style.borderRightStyle = "";
TabPage[i].style.display = "none";
}
TabPage[nTab].style.display = "block";
Tab[nTab].className = "TabSelected";
oTab = Tab[nextTab];
if (oTab) oTab.style.borderLeftStyle = "none";
oTab = Tab[prevTab];
if (oTab) oTab.style.borderRightStyle = "none";
event.returnValue = false;
document.getElementById('hdnTabSelected').value = nTab;
}
function BodyOnLoad()
{
if(document.getElementById('hdnTabSelected').value!=null)
TabClick(document.getElementById('hdnTabSelected').value);
}
</script>
<LINK rel="stylesheet" type="text/css" href="http://localhost/RTS/Includes/Style.css">
</HEAD>
<body onload='BodyOnLoad();'>
<form runat="server">
<TABLE id="Table1" cellSpacing="0" cellPadding="0" width="300" border="0">
<TR>
<td>
<input type="hidden" id="hdnTabSelected" value="0" runat="server">
</td>
<TD id="Tab" onclick="TabClick('0');">A</TD>
<TD id="Tab" onclick="TabClick('1');">B</TD>
<TD id="Tab" onclick="TabClick('2');">C</TD>
</TR>
</TABLE>
<table id="TabPage" class="TabPage">
<TR>
<td>Page1
<asp:Button id="Button1" runat="server" Text="Button"/>
<asp:DropDownList id="DropDownList1" runat="server"/>
</td>
</tr>
</table>
<table id="TabPage" class="TabPage">
<tr>
<td>
Page2
</td>
</tr>
</table>
<table id="TabPage" class="TabPage">
<tr>
<td>Page3
</td>
</tr>
</table>
</form>
</body>
</HTML>
|