Hi,

Here is another issue I'm meeting with my game profiler.

As a quick reminder, my game profiler does inject two method calls to
each methods before and after the actual method body in a given
assembly to store profiled data in static fields that are also added
to the type during the build process.

everything works fine but I have a strange behavior.
Imagine the following solution:

Indiefreaks.Game.Framework Project (dll assembly)
--- Application class
------- Update virtual method
------- Draw virtual method
--- IUpdate interface
------- Update method
--- IDraw interface
------- Draw method
--- GameState class implements IUpdate & IDraw
------- IUpdate.Update method (explicit implementation)
------- Update virtual method (called by IUpdate.Update)

Commander game (exe assembly)
--- CommanderApplication class inherits from Application
------- Update method overrides Application.Update
------- Draw method overrides Application.Draw

My first problem is that when I inject my profiling code in both
assemblies, my CommanderApplication.Draw method does include the right
code (verified in Reflector):

protected override void Draw(GameTime gameTime)
{
    __profilerAttribute132.ProfilingMethodStart(this, (MethodInfo)
MethodBase.GetCurrentMethod());
    base.Draw(gameTime);
    __profilerAttribute132.ProfilingMethodEnd();
    ProfilingManager.Update();
}

And here is the IL code:

.method family hidebysig virtual instance void Draw(class
[Microsoft.Xna.Framework.Game]Microsoft.Xna.Framework.GameTime
gameTime) cil managed
{
    .maxstack 8
    L_0000: ldsfld class
[Indiefreaks.AOP.Profiler]Indiefreaks.AOP.Profiler.ProfilerAttribute
Indiefreaks.Commander.CommanderApplication::__profilerAttribute132
    L_0005: ldarg.0
    L_0006: call class [mscorlib]System.Reflection.MethodBase
[mscorlib]System.Reflection.MethodBase::GetCurrentMethod()
    L_000b: castclass [mscorlib]System.Reflection.MethodInfo
    L_0010: callvirt instance void
[Indiefreaks.AOP.Profiler]Indiefreaks.AOP.Profiler.ProfilerAttribute::ProfilingMethodStart(object,
class [mscorlib]System.Reflection.MethodInfo)
    L_0015: ldarg.0
    L_0016: ldarg.1
    L_0017: call instance void
[Indiefreaks.Game.Framework]Indiefreaks.Xna.Core.Application::Draw(class
[Microsoft.Xna.Framework.Game]Microsoft.Xna.Framework.GameTime)
    L_001c: ldsfld class
[Indiefreaks.AOP.Profiler]Indiefreaks.AOP.Profiler.ProfilerAttribute
Indiefreaks.Commander.CommanderApplication::__profilerAttribute132
    L_0021: call instance void
[Indiefreaks.AOP.Profiler]Indiefreaks.AOP.Profiler.ProfilerAttribute::ProfilingMethodEnd()
    L_0026: call void
[Indiefreaks.AOP.Profiler]Indiefreaks.AOP.Profiler.ProfilingManager::Update()
    L_002b: ret
}

However, the __profilerAttribute132.ProfilingMethodEnd(); method never
gets called while ProfilingManager.Update(); does get called.

I don't understand why. Any clue?
Note that the Application.Draw class calls internally an
((IDraw)ActiveGameState).Draw(gameTime); method.
Here is the Application.Draw code (modified with my injected code):

protected override void Draw(GameTime gameTime)
{
    __profilerAttribute464.ProfilingMethodStart(this, (MethodInfo)
MethodBase.GetCurrentMethod());
    base.GraphicsDevice.Clear(Color.Black);
    if (((this._loadingGameState != null) &&
this._loadingGameState.IsLoadingComplete) && !
this._loadingGameState.ShouldRenderLoadedGameState)
    {
        ((IDraw) this._loadingGameState).Draw(gameTime);
    }
    else if ((this.ActiveGameState != null) &&
this.ActiveGameState.IsLoadingComplete)
    {
        ((IDraw) this.ActiveGameState).Draw(gameTime);
    }
    if ((this._transitionColor.A != 0f) || (this._transitionColor.A !=
1f))
    {
        this._transitionRenderer.Begin(SpriteSortMode.Immediate,
BlendState.AlphaBlend);
        this._transitionRenderer.Draw(this._transitionTexture,
base.GraphicsDevice.Viewport.Bounds, this._transitionColor);
        this._transitionRenderer.End();
    }
    base.Draw(gameTime);
    __profilerAttribute464.ProfilingMethodEnd();
}

My second problem may be related to the 1st one but I'm not sure:

The CommanderApplication.Update normally calls the Application.Update
method (using base.Update()) which in turns calls the internal
((IUpdate)ActiveGameState.Update(gameTime); method.

Here is the code with the profiled injection code:

protected override void Update(GameTime gameTime)
{
    __profilerAttribute463.ProfilingMethodStart(this, (MethodInfo)
MethodBase.GetCurrentMethod());
    if ((SunBurn.Editor != null) && SunBurn.Editor.EditorAttached)
    {
        Input.Enabled = false;
    }
    else
    {
        Input.Enabled = true;
    }
    base.Update(gameTime);
    this.Threads.Update();
    Interpolator.Update((float)
gameTime.ElapsedGameTime.TotalSeconds);
    Timer.Update((float) gameTime.ElapsedGameTime.TotalSeconds);
    if (((this.ActiveGameState != null) &&
this.ActiveGameState.IsLoadingComplete) && ((this._loadingGameState ==
null) || this._loadingGameState.ShouldRenderLoadedGameState))
    {
        ((IUpdate) this.ActiveGameState).Update(gameTime);
    }
    if (((this._loadingGameState != null) &&
this._loadingGameState.IsLoadingComplete) && !
this._loadingGameState.ShouldRenderLoadedGameState)
    {
        ((IUpdate) this._loadingGameState).Update(gameTime);
    }
    __profilerAttribute463.ProfilingMethodEnd();
}

What is strange is that the _profilerAttributeXXX.ProfilingEnd()
methods in CommanderApplication and Application Update methods get
called before the GameState.Update() one:

Commander.exe Information: 0 : Started Profiling
CommanderApplication.Update
    Commander.exe Information: 0 : Started Profiling
Application.Update
    Commander.exe Information: 0 : Ended Profiling Application.Update
Commander.exe Information: 0 : Ended Profiling
CommanderApplication.Update
Commander.exe Information: 0 : Started Profiling
GameState.Indiefreaks.Xna.Core.IUpdate.Update
...
Commander.exe Information: 0 : Ended Profiling
GameState.Indiefreaks.Xna.Core.IUpdate.Update

I was expecting to get the methods called this way instead (that's the
way they actually are run by the game):

Commander.exe Information: 0 : Started Profiling
CommanderApplication.Update
    Commander.exe Information: 0 : Started Profiling
Application.Update
         Commander.exe Information: 0 : Started Profiling
GameState.Indiefreaks.Xna.Core.IUpdate.Update
         ...
         Commander.exe Information: 0 : Ended Profiling
GameState.Indiefreaks.Xna.Core.IUpdate.Update
    Commander.exe Information: 0 : Ended Profiling Application.Update
Commander.exe Information: 0 : Ended Profiling
CommanderApplication.Update

I hope you can help me understand these behaviors and how I could
solve them.
Thanks

-- 
--
mono-cecil

Reply via email to