Jump to content

Rage recordperformance


khorio

Recommended Posts

I use System.Diagnostics.Stopwatch to measure time of execution of specific parts = I profile problematic spots instead of checking the exec time of the plugin from A to Z.

public static void LogPerformanceStart(string id)
        {
            if (!Transportation.Configuration.LOG_PERFORMANCE) return;

            if (_performance.ContainsKey(id))
            {
                _performance[id].Restart();
            }
            else
            {
                System.Diagnostics.Stopwatch s = System.Diagnostics.Stopwatch.StartNew();
                _performance.Add(id, s);
            }
        }

        public static void LogPerformanceStop(string id, string description)
        {
            if (!Transportation.Configuration.LOG_PERFORMANCE) return;

            if (!_performance.ContainsKey(id)) return;

            _performance[id].Stop();
            LogPerformance(description, _performance[id].Elapsed.ToString());
        }

 

I use it this way:

LogPerformanceStart("mainLoop");

//loop code

LogPerformanceStop("mainLoop", "[Main] Main loop exec time");

 

In terms of optimization: pay attention to not to create a new instance of a Stopwatch in every tick. It might slow your mod.

Edited by LtFlash
Link to comment
Share on other sites

So i had massive lag while my callout was running, i timed everything up to my entire main process, and the highest i got is 5ms.

Is there something else that could cause this slowdown? Or something else i should check?

Link to comment
Share on other sites

5ms can be alot if there's not much code, in my "Transportation" the whole status-bar-drawing class takes ~1ms to get all needed data and draw bars on the screen. It's highly depended on your hardware how different operations influence the performance. You need to review the code, it might create new object(s) inside a loop which SIGNIFICANTLY slows your plugin down. You can post your main loop here so we can take a look and give you more detailed tips.

Link to comment
Share on other sites

Spoiler

public void runthings()
        {
            if (PursuitCreated || checking ) { return; }
            GameFiber.StartNew(delegate
            {
                
                while (true)
                {
                    GameFiber.Yield();

                    
                    if (AreaBlipNeed && Vector3.Distance(Game.LocalPlayer.Character.Position, InitialSpawn) <= 35f)
                    {
                        try
                        {
                            Game.LogTrivial("KC: Entering AreaBlipCheck");
                            AreaBlipNeed = false;
                            if (AreaBlip.IsValid()) AreaBlip.Delete();
                            Game.DisplayNotification("Local security cameras have picked up several ~r~bicycles~w~ in the area.");
                            GameFiber.Sleep(6000);
                            Game.DisplayNotification("The stolen bike is a ~b~" + Common.FirstCharToUpper(StolenBikeModel));
                            GameFiber.Sleep(3000);
                            Game.DisplayNotification("The ~g~Serial Number~w~ of the ~r~ stolen bicycle~w~ is ~g~" + StolenSerial);
                            GameFiber.Sleep(5000);
                            foreach (Ped biker in Bikers)
                            {
                                biker.AttachBlip();
                            }
                        }

                        catch (Exception e)
                        {
                            Common.LogError(e);
                        }
                    } 
                    
                    if (!GotHim && !AreaBlipNeed && Functions.IsPlayerPerformingPullover() && Functions.GetPulloverSuspect(Functions.GetCurrentPullover()).CurrentVehicle == SuspectVehicle && !suspectchecked && !PursuitCreated)
                    {
                        
                        suspectchecked = true;                        
                        GotHim = true;
                        Game.LogTrivial("KC: GotHim");
                        
                    }
                    
                    if (!helpshowed && Functions.IsPlayerPerformingPullover() && !PursuitCreated && Functions.IsPedStoppedByPlayer(Functions.GetPulloverSuspect(Functions.GetCurrentPullover())))
                    {
                        
                        helpshowed = true;
                        Game.LogTrivial("KC: HelpInstructions");
                        Game.DisplaySubtitle("Press ~b~Y~w~ to check the bicycle's ~g~Serial Number~w~.", 6000);
                        
                    }


                    if (!checking && Functions.IsPlayerPerformingPullover() && Game.IsKeyDown(Keys.Y) &&
                    (Vector3.Distance(Game.LocalPlayer.Character.Position, Functions.GetPulloverSuspect(Functions.GetCurrentPullover()).LastVehicle)) <= 3f)
                    {
                        try
                        { 
                            Game.LogTrivial("KC: IsKeyDown");
                            checking = true;
                            Game.DisplayNotification("Checking ~g~ Serial Number...");
                            Game.LocalPlayer.Character.Tasks.PlayAnimation(new AnimationDictionary("missexile3"), "ex03_dingy_search_case_base_michael", 1f, AnimationFlags.None);
                            GameFiber.Sleep(5000);
                            if (GotHim)
                            {
                                CurrentSerial = StolenSerial;
                            }
                            else
                            {
                                CurrentSerial = Common.GenerateBikeSerial();
                            }
                            if (GotHim) { Game.DisplayNotification("Serial number is ~r~" + CurrentSerial); }
                            else { Game.DisplayNotification("Serial number is ~g~" + CurrentSerial); }
                            GameFiber.Sleep(1000);
                            if (GotHim)
                            {
                                Game.LogTrivial("KC: GotBike");
                                Game.DisplayNotification("~b~Dispatch, we have the ~g~stolen bicycle~w~.");
                                Functions.GetPulloverSuspect(Functions.GetCurrentPullover()).PlayAmbientSpeech(null, "GENERIC_FUCK_YOU", 0, SpeechModifier.Force);
                                Pursuit = Functions.CreatePursuit();
                                Functions.AddPedToPursuit(Pursuit, Functions.GetPulloverSuspect(Functions.GetCurrentPullover()));
                                Functions.ForceEndCurrentPullover();
                                Functions.SetPursuitIsActiveForPlayer(Pursuit, true);
                                PursuitCreated = true;
                            }
                            else
                            {
                                Game.LogTrivial("KC: Wrong Suspect");                                
                                Functions.GetPulloverSuspect(Functions.GetCurrentPullover()).Dismiss();
                                Functions.ForceEndCurrentPullover();
                                suspectchecked = false;
                            }
                            checking = false;
                        }
                        catch (Exception e)
                        {
                            Common.LogError(e);
                        }
                        
                    }

                }

            });
        }

 

I know it might not be the most optimized code but its my first plugin :p

Link to comment
Share on other sites

It looks like it shouldn't cause any performance issues. Does your mod influence your frame rate?

What I can recommend is to use switch...case to code any sequential tasks, that's how Rockstar create missions. Here's an example from Wasteland:

Spoiler

private enum EState
        {
            Away,
            Close,
            Action,
            Wait,
        };
private EState state = EState.Away;

public override void Process()
        {
            switch (state)
            {
                case EState.Away:

                    if (LPlayer.LocalPlayer.Ped.Position.DistanceTo(spawn[randSpawn].Position) < 100.0f)
                    {
                        //unused
                        state = EState.Close;
                    }

                    break;

                case EState.Close:

                    if (blipSpawn.Exists())
                    {
                        if (LPlayer.LocalPlayer.Ped.Position.DistanceTo(spawn[randSpawn].Position) < 50.0f)
                        {
                            blipSpawn.Delete();

                            Functions.PrintHelp(msgHelp);
                        }
                    }

                    RunScenario(); //runs different scenarions, can set state to EState.Action

                    break;

                case EState.Action:

                    if (Helpers.CheckExistance(ref suspect1) && Helpers.CheckExistance(ref suspect2))
                    {
                        if (LPlayer.LocalPlayer.Ped.Position.DistanceTo2D(suspect1.Position) < 8.0f)
                        {
                            suspect1.Task.FightAgainst(LPlayer.LocalPlayer.Ped);
                            suspect2.Task.FightAgainst(LPlayer.LocalPlayer.Ped);

                            state = EState.Wait;
                        }
                    }
                    else
                    {
                        state = EState.Wait;

                        FailureEnd();
                    }

                    break;
            }
            
            if (!LPlayer.LocalPlayer.Ped.IsAlive)
            {
                SetCalloutFinished(false, false, true);
                End();
            }

            if ((Helpers.CheckExistance(ref suspect1) && suspect1.HasBeenArrested) ||
                (Helpers.CheckExistance(ref suspect1) && !suspect1.IsAliveAndWell))
            {
                trigStateS1 = true;
            }

            if ((Helpers.CheckExistance(ref suspect1) && suspect2.HasBeenArrested) ||
                (Helpers.CheckExistance(ref suspect1) && !suspect2.IsAliveAndWell))
            {
                trigStateS2 = true;
            }

            if (trigStateS1 && trigStateS2)
            {
                SetCalloutFinished(true, true, true);
                End();
            }

            if (Functions.IsKeyDown(keyEnd))
            {
                LPlayer.LocalPlayer.Ped.PlayWalkieTalkieAnimation("RANDOMCHAT_01");
                SetCalloutFinished(false, false, false);
                End();
            }

            base.Process();
        }

 

to enable >=2 states at the same you can use bit flags:

 

Edited by LtFlash
Link to comment
Share on other sites

Changed it but still having the same issues...really strange

Spoiler

 public void runthings()
        {
            GameFiber.StartNew(delegate
            {

                while (true)
                {
                    GameFiber.Yield();

                    switch (state)
                    {
                        case EState.Offscene:
                            if (Vector3.Distance(Player.Position, InitialSpawn) <= 35f)
                            {
                                state = EState.Looking;
                                if (AreaBlip.IsValid()) AreaBlip.Delete();
                                Game.DisplayNotification("Local security cameras have picked up several ~r~bicycles~w~ in the area.");
                                GameFiber.Sleep(5000);
                                Game.DisplayNotification("The stolen bike is a ~b~" + Common.FirstCharToUpper(StolenBikeModel));
                                GameFiber.Sleep(5000);
                                Game.DisplayNotification("The ~g~Serial Number~w~ of the ~r~ stolen bicycle~w~ is ~g~" + StolenSerial);
                                GameFiber.Sleep(5000);
                                foreach (Ped biker in Bikers)
                                {
                                    biker.AttachBlip();
                                }
                            }
                            break;

                        case EState.Looking:
                            {
                                if (Functions.IsPlayerPerformingPullover() && Vector3.Distance(Player.Position, GetVehicle().Position) <= 3f)
                                {
                                    Game.DisplaySubtitle("Press ~b~Y~w~ to check the bicycle's ~g~Serial Number~w~.", 6000);
                                    state = EState.Checking;
                                    PullOverPed = GetPed();
                                    PullOverVehicle = GetVehicle();
                                }
                                break;
                            }
                        case EState.Checking:
                            {
                                if (Game.IsKeyDown(Keys.Y))
                                {
                                    Game.DisplayNotification("Checking ~g~ Serial Number...");
                                    PlaySearchAnim();
                                    GameFiber.Sleep(4000);
                                    if (PullOverVehicle == SuspectVehicle)
                                    {
                                        CurrentSerial = "The ~g~Serial Number is: ~r~" + StolenSerial;
                                        GameFiber.Sleep(1000);
                                        Game.DisplayNotification("~b~Dispatch, we have the ~g~stolen bicycle~w~.");
                                        state = EState.Arresting;
                                    }
                                    else
                                    {
                                        CurrentSerial = "The ~g~Serial Number~w~ is: ~g~" + Common.GenerateBikeSerial();
                                        GameFiber.Sleep(1000);
                                        PullOverPed.Dismiss();
                                        Functions.ForceEndCurrentPullover();
                                        state = EState.Looking;
                                    }
                                }
                                break;
                            }
                        case EState.Arresting:
                            {
                                GetPed().PlayAmbientSpeech(null, "GENERIC_FUCK_YOU", 0, SpeechModifier.Force);
                                Pursuit = Functions.CreatePursuit();
                                Functions.AddPedToPursuit(Pursuit, PullOverPed);
                                Functions.ForceEndCurrentPullover();
                                Functions.SetPursuitIsActiveForPlayer(Pursuit, true);
                                PursuitCreated = true;
                                state = EState.Pursuit;
                                break;
                            }
                        case EState.Pursuit:
                            {

                                if (PursuitCreated && !Functions.IsPursuitStillRunning(Pursuit))
                                {
                                    End();
                                }
                                break;
                            }

                    }
                }
            }
          );
        }

 

 

Link to comment
Share on other sites

Wow, now it looks much better! I assume you are completely sure you call runthings() only once, not in some kind of loop, right?

Using the functions I posted above, please check how much time takes this part:

Spoiler

 public void runthings()
        {
            GameFiber.StartNew(delegate
            {

                while (true)
                {
                    GameFiber.Yield();
					
                  	LogPerformanceStart("id");
                  
                    switch (state)
                    {
						//cases
                    }
                  
                  	LogPerformanceStop("id", "Some description");
                }
            }
          );
        }

 

 

post the result of "Elapsed" property (it should look like this: "00:00:00.0003365").

Link to comment
Share on other sites

I'm an idiot :p

yeah runthings() was just sitting there in process(), getting called over and over again...thanks a lot man :)

and thanks for the enum example, this will help tremendously.

Now i just need to figure out why this callout isn't ending properly.

Spoiler

[23/05/2016 19:14:16.545] [TRACE] No more suspects useable, aborting chase
[23/05/2016 19:14:16.548] [TRACE] Removing ped from ChaseController #1 (GameplayMandatory)
[23/05/2016 19:14:16.548] [TRACE] Instance cleaned (ChaseController #1)
[23/05/2016 19:14:16.548] [TRACE] Aborted chase
[23/05/2016 19:14:16.551] [TRACE] Instance cleaned ( #1)
[23/05/2016 19:14:16.553] LSPD First Response: Khallouts: An error has occured: System.NullReferenceException: Object reference not set to an instance of an object.
[23/05/2016 19:14:16.554] at LSPDFR_Khallouts.Callouts.BikeTheft.End() in E:\_GTADEV\LSPDFR Khallouts\LSPDFR Khallouts\Callouts\BikeTheft.cs:line 279

 

Apparently Ped.GetAttachedBlip() does not work for some reason, its always null

Link to comment
Share on other sites

Heh, it always was a loop xD If not a loop it's a missing resource. Oh wait...

Is is about a blip or a ped the blip is attached to? The error occurs in End() so I suppose you want to free resources, is that right? ainesophaur is completely right, try to create blip this way:

Blip b = new Blip(ped);

then remove it:

if(b.Exists()) b.Delete();

in Wasteland I always checked if b != null && b.Exists(), it happened to be more reliable.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...