Zazz
Zazz

Reputation: 381

C#/.NET - Very high CPU usage when using async/await function calls

I am having some severe performance issues in a project i'm working on. It's a standard web application project - users send requests to an API which trigger some form of computation in various handlers. The problem right now is pretty much any request will drive the CPU usage of the server up significantly, regardless of what internal computation the corresponding function is supposed to do. For example, we have an endpoint to display a game from the database - the user sends a request containing an ID and the server will respond with a JSON-object. When this request is being processed the CPU usage goes from 5% (with the app just running) to 25-30%. Several concurrent requests will tank the server, with .net-core using 60-70% of the CPU.

The request chain looks like:

(Controller)

 [HttpGet("game/{Id}")]
    public async Task<IActionResult> GetPerson(string Id)
    {
        try
        {
            var response = await _GameService.GetGameAsync(Id);
            return Ok(new FilteredResponse(response, 200));
        }

Service

 public async Task<PlayerFilteredGameState> GetGameAsync(string gameId, string apiKey)
    {
        var response = await _ironmanDataHandler.GetGameAsync(gameId);
        var filteredGame = _responseFilterHelper.FilterForPlayer(response, apiKey);
        return filteredGame;
    }

Data handler

  public async Task<GameState> GetGameAsync(string gameStateId)
    {
        using (var db = _dbContextFactory.Create())
        {
            var specifiedGame = await db.GameStateIronMan.FirstOrDefaultAsync(a => a.gameId == gameStateId);
            if (specifiedGame == null)
            {
                throw new ApiException("There is no game with that ID.", 404);
            }
            var deserializedGame = JsonConvert.DeserializeObject<GameState>(specifiedGame.GameState);
            return deserializedGame;
        }
    }

I've tried mocking all function return values and database accesses, replacing all computed values with null/new Game() etc etc but it doesn't improve the performance. I've spent lots of time with different performance analysis tools but there isn't a single function that uses more than 0,5-1% of the CPU. After a lot of investigation the only "conclusion" i've reached is that it seems to have something to do with the internal functionality of async/await and the way we use it in our project, because it doesn't matter what we do in the called functions - as soon as we call a function the performance takes a huge hit. I also tried making the functions synchronous just to see if there was something wrong with my system, however performance is massively reduced if i do that (which is good, i suppose). I really am at a loss here because we aren't really doing anything out of the ordinary and we're still having large issues.

UPDATE I've performed a performance analysis in ANTS. Im not really sure how to present the results, so i took a picture of what the callstack looks like. enter image description here

Upvotes: 3

Views: 2807

Answers (1)

Mel Gerats
Mel Gerats

Reputation: 2252

If your gamestate is a large object, deserializing it can be quite taxing.

You could create a test where you just deserialize a saved game state, and do some profiling with various game states (a fresh start, after some time, ...) to see if there are differences.

If you find that deserializing takes a lot of CPU no matter what, you could look into changing the structure and seeing if you can optimize the amount of data that is saved

Upvotes: 2

Related Questions