HankG / slimtune

Automatically exported from code.google.com/p/slimtune
MIT License
0 stars 0 forks source link

Multithreading - Threads in WaitSleepJoin state #36

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
There seems to be some strange behavior in sample counts when a thread is 
suspended for example in Monitor.Wait.

Here's a simple console app to illustrate the behavior:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace SuspendTest
{
    class Program
    {
        private static object lockobj = new object();
        private static int step = 0;

        static void WaitForStep(int waitStep)
        {
            while (step != waitStep) Monitor.Wait(lockobj);
        }

        static void Main(string[] args)
        {
            Thread producer = new Thread(() =>
                {
                    lock (lockobj)
                    {
                        do
                        {
                            WaitForStep(0);
                            // generate data
                            for (int i = 0; i < 10000000; i++)
                            {
                                double a = Math.Pow(123, 123);
                            }
                            step = 1;
                            Monitor.Pulse(lockobj);
                        } while (true);
                    }
                }
            );

            Thread consumer = new Thread(() =>
                {
                    lock (lockobj)
                    {
                        do
                        {
                            WaitForStep(1);
                            // process data
                            for (int i = 0; i < 10000000; i++)
                            {
                                double a = Math.Pow(123, 123);
                            }
                            step = 0;
                            Monitor.Pulse(lockobj);
                        } while (true);
                    }
                }
            );

            producer.Start();
            consumer.Start();
        }
    }
}

It basically alternates execution in each thread, majority of time spent 
in the for loop. However the results from profiling return very strange 
results.

A dump of SELECT * FROM Callers JOIN Functions ON CallerId = Id gets

    3   2   4   1954    2   2   0
    System.Threading.ExecutionContext.Run
    (System.Threading.ExecutionContext, 
System.Threading.ContextCallback, object)
    3   3   2   1954    3   3   0
    System.Threading.ThreadHelper.ThreadStart   ()
    3   4   0   19  4   1   0
    SuspendTest.Program.<Main>b__0  ()
    3   4   5   1935    4   1   0
    SuspendTest.Program.<Main>b__0  ()
    3   5   0   1935    5   1   0
    SuspendTest.Program.WaitForStep (int)
    4   1   0   39  1   1   0
    SuspendTest.Program.<Main>b__1  ()
    4   1   5   2009    1   1   0
    SuspendTest.Program.<Main>b__1  ()
    4   2   1   2048    2   2   0
    System.Threading.ExecutionContext.Run
    (System.Threading.ExecutionContext, 
System.Threading.ContextCallback, object)
    4   3   2   2048    3   3   0
    System.Threading.ThreadHelper.ThreadStart   ()
    4   5   0   2009    5   1   0
    SuspendTest.Program.WaitForStep (int)

This agrees with display in per-thread trees visualizer, which indicates 
that about 98-99% time is spend in WaitForStep function. However when the 
thread is in that function it is actually in WaitSleepJoin thread state in 
most cases. Even if it would count samples there one would expect the 
samples in wait to be at about 50% due to the symmetry in the threads. 
Even better would be if there was a switch somewhere to disable collection 
of samples in threads that are in WaitSleepJoin state.

Original issue reported on code.google.com by kavanpro...@gmail.com on 27 Feb 2010 at 10:06

GoogleCodeExporter commented 9 years ago
I've looked into how to get the ThreadState from inside the profiler, but it 
appears 
there's no easy way to do so. The closest I found was this: 
http://social.msdn.microsoft.com/Forums/en-US/netfxtoolsdev/thread/55f3bfc6-ae37
-
4f7d-b7f8-899d9c4c44bc

Original comment by kavanpro...@gmail.com on 1 Mar 2010 at 3:51

GoogleCodeExporter commented 9 years ago
Yeah, it's a bit complicated to do. I'll have to see if I can put the callbacks 
to
good use.

Original comment by promit....@gmail.com on 1 Mar 2010 at 6:10

GoogleCodeExporter commented 9 years ago
I've added experimental support for these callbacks and tracking thread 
state...but honestly, I haven't actually seen the callback get hit yet. Sooo 
yeah, I'm not too sure what to do yet.

Original comment by promit....@gmail.com on 2 Jul 2010 at 6:45

GoogleCodeExporter commented 9 years ago
Oh, I'm also not able to repro your timings; I get pretty close to 50/50 
between the two threads.

Original comment by promit....@gmail.com on 2 Jul 2010 at 6:47

GoogleCodeExporter commented 9 years ago
This has been 'fixed' by the new weighted sampling mode, which biases samples 
by executed thread cycles. It isn't quite the same but accomplishes nearly the 
same goal.

Original comment by promit....@gmail.com on 23 Feb 2011 at 12:17