Tuesday, September 30, 2014

.NET Just in Time Compilation and Warming up Your System

IMG_7823.jpg

One of the primary obstacle we face while scaling our system is Just In Time (JIT) compilation of the .NET stack. We run a .NET managed application server at a huge scale with many thousands of managed assemblies on each server (and many many thousands of those servers distributed globally).We deploy code daily and since those are managed code they are JITed at each deployment. Our system is very sensitive to latency and we do not want those servers getting new code to cost us execution latency. So we use various mechanisms to warm the servers before they start serving queries. Common techniques we use are

  1. NGEN
  2. Force JITing (a specialized multi-core JIT technique see bottom of post)
  3. Sending warmer queries that warm up the system

In this effort I frequently handle questions regarding how the system JITs managed methods. Even after so many years of the CLR JIT existing there seems to be confusion around when JIT happens, what is the unit of compilation. So I thought I’d make a quick post on this topic.

Consider the following simple code I have in One.cs

using System;

namespace Foo
{
class MyClass
{
public void a()
{
int i = 0;
while(true)
{
b(i++);
}
}

public void b(int i)
{
Console.WriteLine(i);
}
}

class Program
{
static void Main()
{
MyClass mc = new MyClass();
mc.a();
}
}
}


Of interest is the function Foo.MyClass.a and Foo.MyClass.b. We will debug to find out exactly when the later is JITed.



First I compile and then launch the debugger. I will use the windbg debugger and the sos extensions extensively in this post. Also read https://support2.microsoft.com/kb/319037?wa=wsignin1.0 to see how to setup symbol servers to debug into the CLR.

csc /debug+ One.cs
windbg one.exe


After that in windbg I run the following command to setup

.sympath+ d:\MySymbols          ;$$ Use the Microsoft symbol server (see link above)
sxe ld:clr ;$$ break on CLR loaded
g ;$$ continue the program until you break on CLR.dll being loaded
.loadby sos clr ;$$ load the sos debugger extension

!bpmd One.exe Foo.MyClass.a ;$$ Set a managed break point in a()
g ;$$ continue until break point in a() is hit



When this break point is hit, we have obviously already JITed MyClass.a() and executing it. The question we now have is that whether all the functions a() calls like MyClass.b() already JITed. If not when/how will that be JITed. Lets debug it!!



**Color coding indicates how I take output of one command to give inputs to the next one.



First lets find the this pointer for the MyClass instance. This can be obtained from the current managed call stack

0:000> !clrstack -a
PARAMETERS:
this (0x0000000000d9eea0) = 0x0000000002922c58



The details of the this object shows the MethodTable for it. The MethodTable has pointer to EEClass (cold data).

0:000> !do 0x0000000002922c58
Name: Foo.MyClass
MethodTable: 00007ffab2f640d8
EEClass: 00007ffab3072340
Size: 24(0x18) bytes
File: d:\Skydrive\Code\C#\_JITPresentation\One.exe
Fields:


Now we can see more details of the MethodTable, which will show the individual methods descriptors.

0:000> !dumpmt -md 00007ffab2f640d8
EEClass: 00007ffab3072340
Module: 00007ffab2f62fc8
Name: Foo.MyClass
mdToken: 0000000002000002
File: d:\Skydrive\Code\C#\_JITPresentation\One.exe
BaseSize: 0x18
ComponentSize: 0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
Entry MethodDesc JIT Name
00007ffb07c16300 00007ffb077c80e8 PreJIT System.Object.ToString()
00007ffb07c5e760 00007ffb077c80f0 PreJIT System.Object.Equals(System.Object)
00007ffb07c61ad0 00007ffb077c8118 PreJIT System.Object.GetHashCode()
00007ffb07c5eb50 00007ffb077c8130 PreJIT System.Object.Finalize()
00007ffab3080120 00007ffab2f640d0 JIT Foo.MyClass..ctor()
00007ffab3080170 00007ffab2f640b0 JIT Foo.MyClass.a()
00007ffab2f6c050 00007ffab2f640c0 NONE Foo.MyClass.b(Int32)


The type has 7 methods. Also the out clearly indicates that Foo.MyClass.a() is JITed and Foo.MyClass.b() is NONE (or not JITed). We can get more details about these methods

0:000> !dumpmd 00007ffab2f640b0
Method Name: Foo.MyClass.a()
Class: 00007ffab3072340
MethodTable: 00007ffab2f640d8
mdToken: 0000000006000001
Module: 00007ffab2f62fc8
IsJitted: yes
CodeAddr: 00007ffab3080170 <----- JITed
Transparency: Critical
i. 0:000> !dumpmd 00007ffab2f640c0
Method Name: Foo.MyClass.b(Int32)
Class: 00007ffab3072340
MethodTable: 00007ffab2f640d8
mdToken: 0000000006000002
Module: 00007ffab2f62fc8
IsJitted: no
CodeAddr: ffffffffffffffff <----- Not yet JITed


So at this point we know that a() is JITed but the method b() it calls is not. In that the question arises that if it is not what is the content of the native instructions for a() and what does that code call into for b(). The disassembly will clearly show that the entire method a() is JITed and that for outward managed calls there are calls to stubs

0:000> u 00007ffab3080170 L24
One!Foo.MyClass.a() [d:\Skydrive\Code\C#\_JITPresentation\One.cs @ 8]:
00007ffa`b3080170 48894c2408 mov qword ptr [rsp+8],rcx
00007ffa`b3080175 4883ec38 sub rsp,38h
00007ffa`b3080179 c744242000000000 mov dword ptr [rsp+20h],0
00007ffa`b3080181 c644242400 mov byte ptr [rsp+24h],0
00007ffa`b3080186 48b83834f6b2fa7f0000 mov rax,7FFAB2F63438h
00007ffa`b3080190 8b00 mov eax,dword ptr [rax]
00007ffa`b3080192 85c0 test eax,eax
00007ffa`b3080194 7405 je One!Foo.MyClass.a()+0x2b (00007ffa`b308019b)
00007ffa`b3080196 e82574b25f call clr!JIT_DbgIsJustMyCode (00007ffb`12ba75c0)
00007ffa`b308019b 90 nop
00007ffa`b308019c c744242000000000 mov dword ptr [rsp+20h],0
00007ffa`b30801a4 eb23 jmp One!Foo.MyClass.a()+0x59 (00007ffa`b30801c9)
00007ffa`b30801a6 90 nop
00007ffa`b30801a7 8b4c2420 mov ecx,dword ptr [rsp+20h]
00007ffa`b30801ab ffc1 inc ecx
00007ffa`b30801ad 8b442420 mov eax,dword ptr [rsp+20h]
00007ffa`b30801b1 89442428 mov dword ptr [rsp+28h],eax
00007ffa`b30801b5 894c2420 mov dword ptr [rsp+20h],ecx
00007ffa`b30801b9 8b542428 mov edx,dword ptr [rsp+28h]
00007ffa`b30801bd 488b4c2440 mov rcx,qword ptr [rsp+40h]
00007ffa`b30801c2 e889beeeff call Foo.MyClass.b(Int32) (00007ffa`b2f6c050)
00007ffa`b30801c7 90 nop
00007ffa`b30801c8 90 nop

00007ffa`b30801c9 c644242401 mov byte ptr [rsp+24h],1
00007ffa`b30801ce ebd6 jmp One!Foo.MyClass.a()+0x36 (00007ffa`b30801a6)
00007ffa`b30801d0 90 nop
00007ffa`b30801d1 4883c438 add rsp,38h
00007ffa`b30801d5 c3 ret
00007ffa`b30801d6 0000 add byte ptr [rax],al
00007ffa`b30801d8 1909 sbb dword ptr [rcx],ecx
00007ffa`b30801da 0100 add dword ptr [rax],eax
00007ffa`b30801dc 096200 or dword ptr [rdx],esp


So we see that for b a call is made to the memory location 00007ffa`b2f6c050. We can see what is there now by disassembling that address.

0:000> u 00007ffa`b2f6c050
Foo.MyClass.b(Int32):
00007ffa`b2f6c050 e87b5e755f call clr!PrecodeFixupThunk (00007ffb`126c1ed0)
00007ffa`b2f6c055 5e pop rsi
00007ffa`b2f6c056 0201 add al,byte ptr [rcx]


So basically instead of real native JITed code existing for b() there is actually a stub or thunk in it’s place. So we clearly establish that when a function is called it’s entire code is JITed and other method it calls is not yet JITed (however, there are caveats like inline methods etc). Now we can now go and set a breakpoint inside JIT to break when it tries it JIT the b() method. This is what we do

0:000> bp clr!UnsafeJitFunction ;$$ entry point for JITing a method
0:000> g ;$$ continue executing until we hit the UnsafeJITFunction
0:000> k ;$$ dump the stack for JITing
clr!UnsafeJitFunction
clr!MethodDesc::MakeJitWorker
clr!MethodDesc::DoPrestub
clr!PreStubWorker+0x3d6
clr!ThePreStub+0x5a [f:\dd\ndp\clr\src\vm\amd64\ThePreStubAMD64.asm @ 92]
One!Foo.MyClass.a()+0x57 [d:\Skydrive\Code\C#\_JITPresentation\One.cs @ 12]


As we can see that the JITing actually happened in the same call thread that is executing a() and exactly when b was called. ThePreStub finally calls the JITer. The JITer will actually JIT the method b() and backtrack the stack and patch up the call, so that it will actually now be a call straight to the JITed copy of b(). We hit g couple of times and now see what happens for the MethodDescriptor for b()

0:000> !dumpmd 00007ffab2f640c0
Method Name: Foo.MyClass.b(Int32)
Class: 00007ffab3072340
MethodTable: 00007ffab2f640d8
mdToken: 0000000006000002
Module: 00007ffab2f62fc8
IsJitted: yes
CodeAddr: 00007ffab30801f0 <-- Now it is JITed
Transparency: Critical


As we see b() is now JITed and we can see it’s disassembly as well. However, more interesting, lets go back and see what the disassembly of a() now contains

0:000> u 00007ffab3080170 L24
One!Foo.MyClass.a() [d:\Skydrive\Code\C#\_JITPresentation\One.cs @ 8]:
00007ffa`b3080170 48894c2408 mov qword ptr [rsp+8],rcx
00007ffa`b3080175 4883ec38 sub rsp,38h
00007ffa`b3080179 c744242000000000 mov dword ptr [rsp+20h],0
00007ffa`b3080181 c644242400 mov byte ptr [rsp+24h],0
00007ffa`b3080186 48b83834f6b2fa7f0000 mov rax,7FFAB2F63438h
00007ffa`b3080190 8b00 mov eax,dword ptr [rax]
00007ffa`b3080192 85c0 test eax,eax
00007ffa`b3080194 7405 je One!Foo.MyClass.a()+0x2b (00007ffa`b308019b)
00007ffa`b3080196 e82574b25f call clr!JIT_DbgIsJustMyCode (00007ffb`12ba75c0)
00007ffa`b308019b 90 nop
00007ffa`b308019c c744242000000000 mov dword ptr [rsp+20h],0
00007ffa`b30801a4 eb23 jmp One!Foo.MyClass.a()+0x59 (00007ffa`b30801c9)
00007ffa`b30801a6 90 nop
00007ffa`b30801a7 8b4c2420 mov ecx,dword ptr [rsp+20h]
00007ffa`b30801ab ffc1 inc ecx
00007ffa`b30801ad 8b442420 mov eax,dword ptr [rsp+20h]
00007ffa`b30801b1 89442428 mov dword ptr [rsp+28h],eax
00007ffa`b30801b5 894c2420 mov dword ptr [rsp+20h],ecx
00007ffa`b30801b9 8b542428 mov edx,dword ptr [rsp+28h]
00007ffa`b30801bd 488b4c2440 mov rcx,qword ptr [rsp+40h]
00007ffa`b30801c2 e889beeeff call Foo.MyClass.b(Int32) (00007ffa`b2f6c050)
00007ffa`b30801c7 90 nop
00007ffa`b30801c8 90 nop
00007ffa`b30801c9 c644242401 mov byte ptr [rsp+24h],1
00007ffa`b30801ce ebd6 jmp One!Foo.MyClass.a()+0x36 (00007ffa`b30801a6)
00007ffa`b30801d0 90 nop
00007ffa`b30801d1 4883c438 add rsp,38h
00007ffa`b30801d5 c3 ret
00007ffa`b30801d6 0000 add byte ptr [rax],al
00007ffa`b30801d8 1909 sbb dword ptr [rcx],ecx
00007ffa`b30801da 0100 add dword ptr [rax],eax
00007ffa`b30801dc 096200 or dword ptr [rdx],esp
00007ffa`b30801df 005600 add byte ptr [rsi],dl


Now if we re-disassemble the target of this call at 00007ffa`b2f6c050

0:000> u 00007ffa`b2f6c050
Foo.MyClass.b(Int32):
00007ffa`b2f6c050 e99b411100 jmp One!Foo.MyClass.b(Int32) (00007ffa`b30801f0)
00007ffa`b2f6c055 5f pop rdi
00007ffa`b2f6c056 0201 add al,byte ptr [rcx]


As you can see the address has been patched up and now b() is JITed and a() calls into b() without going through any stubs.



Obviously in this example I took a bunch of assumptions, but hopefully you now have the understanding to go debug your own scenarios and see what is at play. Some of the takeaways if you have JIT issues at startup



JIT happens at method granularity



Use modular code. Especially if you have error handling and other code which is rarely or almost never used, instead of having them in the main function, move them out. This will ensure that they are never JITed or at best not JITed at startup

void Foo()
{
try{
//...
}
catch(Exception ex)
{
ComplexErrorHandling(ex);
}
}


is better than

void Foo()
{
try{
//...
}
catch(Exception ex)
{
LogLocal();
UploadToSomeServer();
// MoreCode;
// EvenMoreCode;
}
}


For a given function running it once, JITs the whole function. However, do note that if it has difference code branches and each calls other functions you will need to execute all branches. In the case below Foo has to be called with both true and false to ensure downstream methods are JITed

void Foo(bool flag)
{
if(flag)
YesFlag();
else
NoFlag();
}


JITing happens in the same thread as the calls. The JIT engine does takes lock to ensure there is no races while JITing the same method from multiple threads.



Consider using NGEN, MultiCoreJIT or ForceJIT all methods you care about or even build your own mechanism based on the following code



Here’s some PseudoCode to force JIT which accomplishes that using RuntimeHelpers.PrepareMethod API (note this code does no error handling whatsoever). You can craft code around this to ForceJIT only assemblies and/or types in them that is causing JIT bottlenecks. Also this can be parallelized across cores. The .NET Multicore JIT is based on similar principle but automatically does it by generating a profile of what executes at your application startup and then JITing it for you in the next go.

using System;
using System.Reflection;
namespace ConsoleApplication5
{
class Program
{
static private void ForceJit(Assembly assembly)
{
var types = assembly.GetTypes();

foreach (Type type in types)
{
var ctors = type.GetConstructors(BindingFlags.NonPublic
| BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.Static);

foreach (var ctor in ctors)
{
JitMethod(assembly, ctor);
}

var methods = type.GetMethods(BindingFlags.DeclaredOnly
| BindingFlags.NonPublic
| BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.Static);

foreach (var method in methods)
{
JitMethod(assembly, method);
}
}
}

static private void JitMethod(Assembly assembly, MethodBase method)
{
if (method.IsAbstract || method.ContainsGenericParameters)
{
return;
}

System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle);
}

static void Main(string[] args)
{
ForceJit(Assembly.LoadFile(@"d:\Scratch\asm.dll"));
}
}
}

Thursday, September 18, 2014

SuppressIldasmAttribute – The Insanity

Meteors and sky Wish Poosh Campground, Cle Elum Lake, WA

We use ildasm in our build deployment pipeline. Recently one internal partner pinged me saying that it was failing with a weird message that ildasm is failing to disassemble one particular assembly. I instantly assumed it to be a race condition (locks taken on the file, some sort of anti-virus holding read locks, etc). However, he reported back it is a persistent problem. I asked for the assembly and tried to run

ildasm foo.dll

I was greeted with


image


Dumbfounded I dug around and found this weird attribute on this assembly

[assembly: SuppressIldasmAttribute] 

MSDN points out http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.suppressildasmattribute(v=vs.110).aspx that this attribute is to make ildasm not disassembly a given assembly. For the life of me I cannot fathom why someone invented this attribute. This is one of those things which is so surreal…. Obviously you can simply point reflector or any of the gazillion other disassemblers to this assembly and they be happy to oblige. False sense of security is worse than lack of security, I’d recommend not to use this attribute.

Wednesday, August 13, 2014

Hiking Summerland and the Pan Handle Gap

Length: 12.0 miles, roundtrip
Elevation Gain: 2950 ft.
Highest Point: 6800 ft
Link: http://www.wta.org/go-hiking/hikes/panhandle-gap

It’s been 4 years I have been hiking around, but never really kept a log of those hikes. However, on this hike while discussing with some of the folks I suddenly realized I have been forgetting details of some of the past hikes. So I thought I’ll start making short blogs on the hikes/climbs I go on.

I went on this hike with the good people on /meetup.com. It was after a long break because these days I am mostly hiking with my daughter Prokriti and also Somtapa joins us frequently. Both of them are in India for the next 6 weeks. We all met at the Renton park and ride (close to Walmart) and finally reached and started from the trailhead around 10:00 a.m.IMG_7633

This hike starts from the road to the Sunrise visitor center of Mt. Rainier. A few miles before sunrise the trail starts from the bridge over the Frying pan creek.

image

Initially the hike is kind of boring and like any other forest cover hikes. Also kind of flat.

imageThis continues until the first 3 miles where the trail only gains a meager 1200ft. The rest of the 1800 is gained in the next 2 miles. At the 3rd mile there is a scary bridge over a fast and furiously flowing creek. When I climbed the same route 2 years back with Prokriti who was just 7 at that time, it was really really scary. This time around the bridge seemed to be recently repaired and in good condition.

IMG_7612

IMG_7620_PanoAfter this bridge the trail went into relentless switchbacks and reached Summerland at 5900 ft. This part falls on the Wonderland trail that goes around the whole of Mt. Rainier. Summerland is one of the most beautiful meadows I have come across. It has a nice campground as well.

IMG_7706-Edit

IMG_7865

IMG_7849After sitting around here for some time and having food we continued towards the Panhandle gap. Within a quarter of a mile the landscape changed dramatically. It seemed we were instantly transported to a different world of volcanic rocks. The immense powers of the glaciers were evident all around.

IMG_7720

IMG_7847_stitch

IMG_7825-Edit

However, we did not have much time to enjoy the views. The sun was hot and we still had a long way to go. We marched on. Unfortunately I soon discovered that I was getting really low on electrolytes. I started getting cramps and muscle twitch. The heat was getting to me. I also discovered my pack of Nuun electrolyte tabs had fallen off. Thankfully my teammates had some coconut water and Gatorade to share (bless their souls). Replenished I marched on. Finally reached the pan handle gap at 6800ft elevation.

The views were gorgeous. As our lead Ryan said “this is why we do it, if someone doesn’t love this view they should give up hiking”. Also why it’s called a gap was very evident.

IMG_7777_stitch-Edit

IMG_7787_stitch

IMG_7799_stitch

After a long break I headed down to position myself below the Fryingpan Glacier so that I could photograph the other braver souls as they glissaded down.

IMG_7812

IMG_7823

It was a long march home. The 6 miles of tread back seemed never ending!!!

Wednesday, June 18, 2014

Fastest way to switch mouse to left handed

Milky way

 

I think I was born left handed, unfortunately I was brought up to be right handed. This was not uncommon in India 30 years back. Left hand usage was looked down upon.

However, the good thing is I am still ambidextrous (equal handed) in some things like using the mouse. For ergonomic reason I keep switching between left and right hand usage to ensure I do not wear out both my wrists with 12 hour daily computer usage.

The main problem I face when I switch and even otherwise when I am in left-hand mode is that most PC’s are configured for right hand use. In a course of the day I use many machines (upwards of 10) as I remote into data-center machines and even 3-4 local machines. The fastest way I have found to switch between left and right hand mouse is just run the following command either from the console or from WindowsKey+R

rundll32.exe user32.dll,SwapMouseButton

Basically this command calls the SwapMouseButton win32 function in user32.dll.


If you know of anything more brief either using command shell or powershell do let me know.

Wednesday, February 26, 2014

Climbing Mt. Adams

Mt. Adams in the distance

If you are a newbie and want to climb Mt. Adams, this could be the post for you. Adams provides for a very very strenuous but non-technical climb to a really huge peak. The sense of accomplishment is great the risk is low(ish).

19th and 20th July, 2013 we climbed Mt. Adams. At 12,281 ft (3,743m) this is the second tallest mountain in the state of Washington after Mt. Rainier (14,411 feet). I am a complete newbie to hiking and could’ve never imagined an year ago that I can accomplished this. In this blog I will try to chalk out what went right and wrong and how a newbie hiker can accomplish this. If you are an expert hiker, you should always ignore blogs like these, put on your 5 finger Vibram and run up Adams in a day.

Preparation

Obviously this will vary based on one’s personal fitness level and also how much time you are prepared to spend on this. I have been hiking for 2 years. This being the second year. Last year the biggest hike I did was Mt. St. Helens in the summer and even this year I again did Helens in the winter (post to follow).

After talking to various hikers and climbers I figured out that the obvious challenge is to hike up to base camps with large backpack, sleep just couple of hours and then do an equally strenuous hike the next day. I am not that big into exercise, I run a bit, do weights a bit and in general hike a lot but slowly with my family and my eight year old daughter. All in all not in really bad shape but not a typical PNW (Pacific North West) hiker :).

Other than starting to run couple of times a week (around 3.5 miles on the road) I started doing back and core exercises to strengthen my upper body. I hiked almost every weekend or after work. These hikes were mostly hikes like Mt. Si, Granite or Bandera which hovered around 8 miles (roundtrip) with around 3500ft gains. I generally had a backpack with 25lb in it.

Closer to hike day I did couple of hikes up Mt. Si with 50lb backpack. I filled the pack with water. The great thing about doing that is, you can throw the water on the top of the peak and save your knees from the brutal hike down.

image

If you can hike up Mt. Si in 2 hours with a moderate 20lb pack or under 3 hours with a 40 lb pack, you should be good to go.

ICE-AXE self-arrest

Knowing how to do this is a must for Adams. I had to self arrest twice on this trip. First while glissading down when I spun out of the glissade chute. Second on the crescent glacier while we got stuck on a steep section and had to slide down the slope.

 

Gear

This is what I carried for this trip. I had accumulated most stuff over the past year or two and rented the rest from REI. I built my list by consulting various web-sites. One good one was https://www.alpineascents.com/pdf/adams-climb-gear.pdf.

Food/Water

  • 2L Water bladder (Platypus)
  • Extra Nalgene bottle
  • Gatorade powder
  • 6 energy bars
  • Mountain House Food Pouches, one for each meal
  • Gummy Bears (two packets)

Climbing Grear

  • Hiking poles + basket
  • Ice axe (Grivel)
  • Crampons (rented)
  • Plastic Climbing shoes (rented)

Misc

  • Sun-block
  • Lipscreen (SPF 30)
  • First-aid
  • Gorilla tape
  • Emergency blanket
  • Knife
  • Matches
  • Slippers
  • Sanitizing wipes
  • Wag-bag
  • Ear plug (camps are noisy)
  • Garbage Bags

Utensils/appliances

Gadgets

  • Camera
  • GPS (Garmin Oregon 550)
  • Headlight
  • Extra cells for everything
  • Walkie-talkie / two-way radio

Shelter

  • 4 Season tent
  • 20 degree down sleeping bag
  • Sleeping pad

Clothes

  • Hard shell (Gortex based shell from NorthFace)
  • Insulation (800 fill down jacket)
  • Synthetic base layer
  • Long underwear
  • Hiking pant (water resistant)
  • Rain shell pant (for glissading down)
  • Balaclava
  • Snow gloves
  • Running gloves (fleece)
  • Sun glasses (< 8% transmission)
  • Woolen socks
  • Sock liner (to avoid blisters)
 

003The biggest blunder I did in the selection is that I got the cheapo rented plastic boots from REI. Worse still I decided to hike up to base camp wearing that (instead of using hiking boots and packing the snow-boots in). I had blisters two miles into the hike and I think the choice of wearing 4 lb each boots almost ruined our climb. The photo is of me taking care of blisters. I just put in a band-aid and covered it with gorilla tape (yep) and it remained in place. I also taped around the hot-spots in the feet to prevent further blistering.

Save yourself all of the trouble and buy good mountaineering boots.

Starting out

We started our drive from Seattle early in the morning, around 4:00 a.m. We reached the rangers office (2455 Washington 141, Trout Lake, WA 98650) at around 9:30 (with a breakfast stop in between). We collected our climbing passes and drove up to the trail-head at 5500ft. 001_1

Climbing Begins

We went to the restrooms the final time and put on our plastic boots (ouch!) and started our climb at 11:10. The initial part is through forest completely burnt with a forest fire last year.

001

At the beginning of our trip we were all smiles. The route was dusty. 1.5 miles in I had to take off the plastic shoes, put on Band-Aids and gorilla tape and continue to push forward. The combination of huge packs and 4 lb a piece of plastic boots were killing us.

We had some gorgeous views of St. Helens on the way as well. There were patches of snow around but non on the trail.

004

Around 12:20 at 6600ft 2.4 miles into the hike we hit snow. We decided we didn’t really need any crampons because the snow was really mushy.

DSCF0217 We hung around for some time had our first energy bars and started the climb again.

005 The sun was beating down and up (snow reflected) on us. The soft snow was really really hard to climb through. We were in the middle of the crescent glacier. On the way we met quiet a few climbers. One was from Pharmaceuticals background and shared with me how Indians have a mutation which makes our hearts weak (I have heard of this before). It was not encouraging especially we were in a very steep slope and continually slipping. We had a big incident here on the way down, but more about that later.

Around 2:30 at 7700 ft we hit a really rough spot. It was super steep and the snow was so soft, I kind of thought we would not be able to make our way up. From there till 8200ft was nightmarish. When I finally reached the top of that lip it was a huge but short lived relief.

image  DSCF0234

Finally the tough spot was over at 3:23 at 8261ft. There were some camping spots at this place as well, but they were all vacant. We bade our friend Gaurav temporary farewell as he pushed forward to reserve camping spots for us. Yaniv and I were wimps and rested here for some time, took a bunch of photographs and finally after 30 mins continued up the Crescent glacier.

6.5 hours, 5.2 miles, 3800 feet gain later we setup our camp at an elevation of 9300 ft at around 5:40 p.m. Gaurav had chosen a spot on “Lunch Counter” on a dry spot as close to the face of the mountain as possible and just beside the glacier so that we had snow to melt for water easily.

DSCF0242 DSCF0246

Yaniv actually went to sleep. We have photographic proof.

We got down to the business of setting up camp. We were told that there is a stream of water, but it was too thin and we weren’t able to use it well. So I also melted some water and made some nice chai. We had two tents setup for 3 people. I got the royal treatment and got a tent to all by myself.

 009 010011

Our plan was to make dinner, eat and sleep early. However, the sun decided to set. It was so gorgeous we forgot everything and just got busy taking photographs.

IMG_0696-Edit 014

Finally we did go to sleep around 11:00 p.m.. The ear-plugs helped

In no time it was time to get up. We got up at 2:30 a.m.. Made some quick breakfast by boiling water and putting it in the mountain house meal packets. Got dressed and setup for climbing by 3:40 a.m. I was fatigued before even I started my summit day. The combination of sleeping just 3 hours the night before (due to early start from Seattle), 6 hours of climbing and a repeat night of 3 hours of sleeping was too much for me. In my mind I already gave up. The daunting view of the climb to Piker’s peak didn’t help.

However, not willing to let fellow climbers down, I put on the head-lamps, crampons and started out.

We were going up very steep slopes and Yaniv was already not feeling that well. He took some breaks to slow down. The sun was rising and it lit Mt. Hood in golden colors.

 018 019 020 022 021DSCF0295

Yaniv was not feeling well and altitude sickness caught up to him. He was having trouble breathing. Sadly we bade him farewell and decided to keep contact over radio.

Finally around 7 a.m. we reached Pikers peak at 11,500. The look down was very encouraging, I was mind blown that we got up so high. .

 DSCF0310 DSCF0313

However, then I turned around and looked at the real peak. It was super far off. I will remember that point for my whole life. I was completely beat, I had thought we almost made it and there was only a little further to go. But now I realized the last 800 feet was almost impossible for me. I was ready to give up.

DSCF0314 

At this point, Gaurav said, lets not plan to go to the summit. Lets just go to the bottom of the real  peak and then re-consider. We went on thinking this way for the next three phases. It always looked daunting when we looked up, and so I choose to just stare at my feet and take each step at a time…

DSCF0316

Finally we reached summit at 8:40 a.m. It took us 5 hours to summit.

026

 028DSCF0330

030

We dropped our bags and strolled around the summit. We could see St. Helens, Rainier and Hood far off.

We turned back and started the slow march down. I had lot of fun glissading down, but it was very scary at places. It was hard to see what was ahead and I spun out of the glissade chute multiple times and had to self arrest with the ice-axe. Finally we broke the camp and started moving down from there.

029 DSCF0365 IMG_0734

I have always heard that a lot of accidents happen on the descent. We got a taste of it first hand. By the time we reached the steep descent in Crescent Glacier the snow was very soft in the strong sun. We could see rocks jutting out of the snow and since we couldn’t see what was beyond certain points we decided to hike down and not glissade. Soon we were at a steep section which was too soft to stand and we were slipping. Our Ice-axe was still attached to the backpack. Gaurav feel first and hit a huge rock spraying debris. His backpack and poles came off and slid down. Thankfully he was not hurt. We tried to walk a bit further and realized we just cannot make it and once we were clear of the rocks we slid down. When we were at the bottom we realized we should’ve just glissaded down in the first place. A ranger coming up had seen us fall and he stopped by to see if we were safe.

image

After a long long hike we finally reached the trail head and drove back to Seattle. The most dangerous part of our trip was the drive back. The driver actually fell asleep. Looking back we should’ve just slept at the lunch counter and enjoyed the mountains and not tried to drive back.

The partial climb profile is here…

image