Android Stutter, no steady 60 fps

I created a simple project to test Monogame on Android.
It’s a simple square moving across the screen. Besides being not
FixedTimeStep the movement looked laggy. I added a fps log
and observed jumping frametimes.

I ran this code on a Nexus 6 and Nvidia Shield Tablet both on Android 6.0.1.
Is this a known issue and is there a way to resolve it?
I attached my code below.

The fps log shows the following with an empty screen (no touch):

[0:] 37,8277776937161
[0:] 61,445442591523
[0:] 44,8865268600977
[0:] 41,554642276862
[0:] 48,3799958393204
[0:] 34,3719387492052
[0:] 45,1326674760458
[0:] 37,8303535624844
[0:] 44,59070194683
[0:] 46,2705904127337
[0:] 41,9431418768717
[0:] 51,318368896963
[0:] 56,7057369194041
[0:] 61,6340417139194
[0:] 43,6637368299254

I noticed when touching the screen the fps
comes more stable until releasing the finger (with touch):

[0:] 56,0616678346181
[0:] 53,591429658569
[0:] 65,5093350802489
[0:] 64,6274550354482
[0:] 74,0258202060879
[0:] 40,1679018296479
[0:] 108,335319480857 <---- How is this even possible on a android device vsyncing at 60 fps
[0:] 57,3841986870495
[0:] 56,1545372866128

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;

namespace MonoGameLagTest
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

    SpriteFont font;

    public Game1()
    {
        IsFixedTimeStep = false;
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";

        graphics.IsFullScreen = true;
        graphics.PreferredBackBufferWidth = 800;
        graphics.PreferredBackBufferHeight = 480;
        graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
    }

    protected override void Initialize()
    {
        base.Initialize();
    }

    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);

        font = Content.Load<SpriteFont>(@"TestFont");
    }

    protected override void UnloadContent()
    {
    }

    protected override void Update(GameTime gameTime)
    {
        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        spriteBatch.Begin();
        Debug.WriteLine((1.0d / gameTime.ElapsedGameTime.TotalSeconds).ToString());
        spriteBatch.DrawString(font, (1.0d / gameTime.ElapsedGameTime.TotalSeconds) + "fps", Vector2.Zero, Color.White);
        spriteBatch.End();

        base.Draw(gameTime);
    }
}

}

Monogame also has an inconsistent frame rate on my Android phone, even with the default empty project, but I’m using a very low spec phone, so I kind of just assumed that that was the cause of it.

I expected it to be my fault (not setting some flag), since I thought a lot of people would have noticed it, if it was a bug.
I also confirmed the behaviour with a OnePlus One on 6.0.1. I’ll test it on an older version of Android in the emulator now.

When running the app on the emulator a more stable framerate can be observed:

All Hardware Emulation

Nexus 6 Android 5.1.1 Emulator
[0:] 58.9890457342072
[0:] 59.6637351884777
[0:] 61.8685540700228
[0:] 59.9926808929311
[0:] 57.4924110017478
[0:] 63.457413729646
[0:] 58.7430169238632
[0:] 60.5425826254896
[0:] 57.8723798280033
[0:] 64.1782615392514
[0:] 56.0563253957577

Nexus 6 Android 6.0.1 Emulator
[0:] 60.7688474580391
[0:] 58.9685226026347
[0:] 62.4336642317538
[0:] 60.2663773880552
[0:] 38.4917396726662
[0:] 137.379621107005
[0:] 59.7853705198338
[0:] 59.2118897474613
[0:] 61.3139581225666
[0:] 59.6178495841655
[0:] 60.0712444959722

Nexus 5 Android 4.4.4 Emulator
[0:] 59.6466532262875
[0:] 58.1804641637431
[0:] 62.1449967063152
[0:] 61.1153552330023
[0:] 57.2645852898733
[0:] 63.1229445591178
[0:] 61.6211286525924
[0:] 59.1757994650508
[0:] 58.562409960294

I submitted this as an issue on github.

This looks like an issue with garbage collector. Avoid int.ToString(), float.ToString(), string Concatenation, etc. All the above generate new string objects which trigger the garbage collector every few frames. Allocate a StringBuilder once and use it to build your strings.

See the code at https://github.com/tainicom/XNALibrary/blob/master/Source/Helpers/NKStringBuilder.cs as an example.

I also had setup a sample without any string output. I drew a black texture when my fps dropped below 40 and it this indicated the same issue even without any object creation.

It looks like this related to the cpu changing it’s frequency on the devices when no user interaction is happening.
When changing the cpu governor from interactive to performance (all cores at max freq.) the issue is gone.
I tried setting an all wakelook but the cpu still lowers its frequency.