mergeconflict318 === [00:00:00] James: Frank, let me tell you that after last week's podcast, we sat down, you plus me and debugged and analyzed the performance of my application. So let's give a quick recap here. Last week, we talked about performance monitoring, you know, optimizing your application, all this stuff that you should really be doing that I've never done. At the very end. I said, this is pretty of the moment because someone said that my application's using a bunch of CPU and then I ran my application and it was using a bunch of CPU. So then we ended the podcast, Frank, and we used the stuff that we talked about on the podcast. Like we applied 30 minutes of content to debug the issues of my applic. [00:00:55] Frank: It was pretty excellent aside from the fact that I was still dripping sweat by the gal. And I was just dying, James, we had made it through that podcast. It was a good show. I was excited and you're like, Hey, let's sit down for a couple hours and debug this problem I'm having. I'm like great James. Great. It was, it was actually fun because, um, we, I think we ended the podcast and we were using. Task manager. And I was looking at like activity monitor on Mac, and those are great little tools. And I had mentioned CIS internals, but what you really want is a good profile or a good, uh, yeah, a good profiler. Fortunately for you, you have a windows app and sense visual studio, what like 18 or something, every time you hit debug, there's a cool performance graph that comes up. And I. James, you just go look at what that graph says, cuz that graph is just gonna tell you everything that your app's doing. It's a really cool built in feature. [00:01:48] James: So we. And that's the, uh, feature that I minimize immediately and I never pay any attention to until terrible last week. And then it actually solve it. So the, the, this is the timer at my stream timer. Now there's legacy here. So for some reason, over the years, as I've added more features and done more things, I used to have a very simple timer mechanism. So system timers would update every second and I had an issue. Where, uh, for some reason when I was in OBS, which is open broadcast software, which is what we use for streaming, uh, how this works and how my stream timer works is it basically writes the, a current countdown or count up or time to a file. And the reason I do this is because OBS can read. From a file and display it. It monitors that file for changes and then updates a label. So this is nice if you have like stream is count starting in five minutes. And instead of having to do like a custom animation or render things, uh, you can use my stream timer. And then you can like add minutes or add seconds or count down to a specific time. So it's, it gives you a lot of flexibility and it's very accurate compared to, oh, here's a countdown from three minutes and go, if, if you gotta run and make a coffee, you can add, add two minutes and then Nick can go ahead and add those two minutes up there and also does countdown and stuff like that. So I think for some reason, in my mind, I don't know if it was the timer that I was using or Matthew Liebowitz convinced me to switch over. But over the years I switched to. Like task, ongoing task, just, Hey, you're a task. You're just running start new task factory and update the timer and run it and run it. And for some reason I had changed that to, Hey, update that to every 300 milliseconds and just output that to the file because I was like, I wanna be accurate. Right. Just keep going. [00:03:49] Frank: It's a good idea. Uh, we, we have to pause and now talk about performance and talk about correctness. Yes. Now for a minute, we have to, because I'm, I'm really interested in this stuff. Um, I did digital controls and a lot of digital controls is timing and making sure things happen at the right time and all that kind of stuff. So kind of really into all this stuff. How, uh, let's talk about that. OBS, not updating now aside OBS is ridiculous. If sorry, if you don't know what OBS is, uh, open broadcasting system, it's like a big video mixer that we all use for broadcasting. And that has that weird import thing where you just point it at a file and that's why your app updates the file. And then it gets updated on the screen. It's a janky setup. so it's a little bit miraculous that it all works, but whatever we'll put all. Um, aside, ha have you ever heard of something called sampling theory or Shannon's theory of sampling? Anything [00:04:44] James: like that? I don't think so. [00:04:45] Frank: No. Hmm. But you've probably heard of aliasing right. You've seen that [00:04:50] James: like anti [00:04:51] Frank: aliasing. Anti aliasing is removing the aliasing. Yeah. So the alas thing you've seen probably is like, you try to draw a line on the screen with pixels and it comes out all jaggedy. Yes. Call that aliasing that's aliasing anti aliasing is the technology you use to try to make that look smooth, smooth, smooth, smooth it out. Yeah. Smooth it out. Uh, so the problem. Aliasing occurs when you have a high frequency signal and you are sampling at, at too low of a frequency. Ah, And what happens is you just miss parts of the signal or you oversample other parts of the signal. You're not getting a good, true representation of the signal. So, uh, Shannon's an old mathematician that came up with a theoretical, uh, lower limit. If you wanna sample a signal, no, you have to sample at minimum twice the F. Of the signal minimal, theoretically, this is, this is mathematics and physics talking, you know, information theory, uh, ideally you sample it much higher. In fact, um, eight times, 10 times, 20 times, things like that. Um, and those are just to smooth out the signal even more. So what anti Aing software does in the video world is if we're still stuck with the resolution of the screen, the resolution of these screen, Is too low. They are, uh, crossing this threshold that you're supposed to be, uh, sampling at. And so we come up with fake techniques like, uh, multis sample anti, who is saying to fix it, multis sample, we're taking more samples. That's how you fix it. More samples. So, James all, that was a very long way of saying if you have a one hurt signal that you're trying to sample and you are, it's called a clock beat tick. Tick. That's a one hurt sample that you are. You're trying to sample it minimum. You should be sampling at, uh, two hurts theoretical minimum because you might miss a transition. Otherwise you can imagine if you're sampling one hurts at one hurts, then it really matters. Exactly. If you are in phase with each other, you have to be resynchronize with each. Perfectly for a one hurt signal to sample a one hurt signal it's just not ever gonna happen. So what you really wanna be is two hurts, which would mean a 500 millisecond delay. You chose a 300 millisecond delay, which gives you a, a three X. Which is good. It actually puts you within the sampling theorem limits. That's good. But honestly, for an app like this, you can easily do, um, 10 times a second and really not use much CPU, especially if you throw in a few other tricks. So all that's to say, um, It's okay. I could even go deeper. It's even worse than that because the you're you're sampling a digital signal, which means it has infinitely strong phase boundaries, which means you actually need an infinitely high clock, but we won't get into that. Cause it's complicated. Um, look up phase lock loops, everyone if you're interested in that kind of stuff. So all I wanna say is, yeah, the naive approach of a one hurt timer, trying to do a one. Clock tick is not actually your best bet. You actually want to be a little bit faster than that. Uh, unfortunately you changed the technology and introduce some other bugs along the way while you were doing that. [00:08:07] James: so you were very smart and you said, Hey, let's, let's use the, the profiler. Let's see the CPU usage. And let's see if you. The user is accurate because just because the CPU, you know, and my task manager is showing me that it's at like 5%, is it actually at 5%? Or is it just timing up and down? Because the ideal scenario is, is a heartbeat of this thing, right? So if I'm every, you know, quarter of a or every third of a second, ideally would see a spike up spike. Spike up. It should just be like spikes like B up B up. Yeah, B up. It shouldn't, it shouldn't be a plateau, cuz that would be. [00:08:51] Frank: And, and this is really important to do. I, I, I like the scientific method of come up with a hypothesis before you measure it. It's just a way more efficient way to get things done, because I, I kept saying this to you, James, look for spikes. look for a peak and then look for zero peak zero, cuz that's what your app should be doing. It should be waking up doing a bit of work, really small amount of work and then going right back to sleep and going back to zero. So we had, we both had the same hypothesis of we're just looking for a bunch. Peaks. And if we don't see a bunch of peaks, then something's wrong. [00:09:22] James: Correct. And in fact, um, we saw the inverse of a peak. We saw. We literally saw we saw Mesa's. Yes. Um, so that seemed bad in general. And, uh, so we tested a bunch of theories and we said, you know, Frank said, well, let's see if there's something wrong with your logic. Right. So set that weight to five seconds, right. Or whatever, and see if there's something wrong. How long is this code running for? And when we ran and put it at five seconds, sure enough, we. Larger peaks every five seconds. So we said, oh, that's, that's fascinating. So something awry is, is happening in this code because what you told me then was James, actually your app should pretty much not use any CPU at all. It's kind of shenanigans that it should use any CPU because it's, I, it's not updating, it's updating a label on the screen and writing to a disc that should be yeah. The most, it should be a trace amount. [00:10:24] Frank: Yeah, like it, it should be to the point where the profiler should have a hard time seeing it. So most sampling profilers that we use sample at a thou uh, one killer, a thousand Hertz. So they take a sample a thousand times a second. I'm like, there's a good chance your coach should be running. Under a millisecond in time. Now you are writing to disk though. Uh, I, I, wasn't thinking of that and writing to dis can be painfully slow sometimes. And it, it's not your fault as a programmer, you're going through 8,000 levels, layers of software and you never know cash states and all that stuff. Um, so I did mention other things about compensating for that too, but in general it should have been, yeah, pretty, pretty much instantaneous. [00:11:07] James: You know, you gave me the good tip, which is like, we've debugged it. We said that there's a clear issue here. Something is going on. Um, is it, is it my loop logic? Is it something else? And we, we missed the actual issue and we'll get to the actual issue, but you said, well, like, you know, just change it back to a timer and let's see if that fixes it, because sure enough, if you put it on a, a second timer and if, and if it then is being updated every second, For example, and you see the issue then really, really something is wrong because it should, then it should really be a heart, you know, heart tick every single second on the dot cuz is there a problem with my task or is just something with the logic or is it something else? So we took the chunk of code. I shoved it into my, uh, into a timer, which I already had set up. Cause I used it originally flipped on the timer. Two, three lines of code change and boom, Frank. Gave me peaks every second peak peak peak, peak peak. [00:12:07] Frank: And it was more important. Good. More importantly, zeros, lots of zeros. cuz your app should not have been doing anything between those peaks. Yeah. And I, I just wanna sing the praises of timers real quick. I don't know if people understand, these are like fundamental operating system things, usually something like, um, system dot task dot thread system, threading task, you know, things like that. Those are libraries. Running on top of very primitive, um, operating system, primitives threading, primitives mm-hmm uh, a timer is usually one of those very primitive things, uh, to the point where if you're the operating system, if you're the Ker. You are scheduling all these processes to run. You keep track of which processes have active timers. They are that kind of low level of a function. Whereas if you're just using threads and you're just spinning in a thread and doing like a thread dot sleep, Sure. The operating system sees you have a, an awake thread, but that's kind of inefficient. You're using up an entire thread resource just for that. It's almost like a secondary process just for that. Whereas it could just be a light little timer that is a fundamental operating system resource that the scheduler knows how to deal with. And the scheduler can. Pretty accurate with that timing. If you do like a, uh, task dot delay, 1000, meaning I want a one second delay. You are gonna delay for one second and 15 milliseconds or one second and 20 milliseconds. You are never gonna, um, delay. One second. It's there's just too much latency in the kernel. It's not a real time operating system. You're not guaranteed to get woken up at a very specific time. Unless James, you use a timer , which is designed for a very specific wake up time. Now you might still be, um, one second and two milliseconds because maybe.net will have some overhead or, um, whatever. Some user mode software we'll have some over. Or you might get accidentally scheduled out or something like that. But the point I'm trying to make is timers are a nice, fundamental, low level kernel thing. And if you can use a timer, I do recommend those over doing a task dot delay inside of a infinite task. Even though they're functionally vaguely equivalent, there are some fundamental, low level reason. Prefer one over the other. [00:14:34] James: Well, and the other thing that you told me was sliding time, because what I didn't calculate for when I was, um, using my task out delay, and I was, let's say delaying for a second, not only does that have a little bit of implication, but I wasn't taking into account the milliseconds that it was taking to execute. My logic and my code in writing to disk. So if that right to dis, for some reason, took a hundred milliseconds. That means that update and the TASS delay would be 100 or 1,100 milliseconds. So whoa, like a big, another big issue diagnosing this code is like those beats may not be every second where a timer is going to call that method every second. [00:15:21] Frank: What do you want to or not? So you better be reentering yeah. Uh, it's tricky. So what you were just talking about is a whole different synchronization thing. So the, what I was complaining about with the, uh, test dot delay is that it's, you're not guaranteed precision on that delay. You're guaranteed an overshoot, but never an undershoot at least. And so if you. If you wanna do something resembling real time software, where you're actually hitting a beat pattern right. On the dot, like, if you're doing something with audio, I've had to do this, uh, for that for audio and ice circuit. Yeah. Sorry. Uh, and then control loops like robotics and it just comes up all the time where you got the state. In sync, it's very important. And the only way to do that is with a kind of a feedback loop where you measure exactly how long your software took. You can even measure, uh, if you do it cleverly, how long it takes, uh, the latency of the operating system. So you measure how long your code takes, you measure the latency of the operating system, and you can really tune that. And I've, I've tuned it down to a couple milliseconds. Let's say you can get on an operating system like windows or Mac. That to be clear, were not designed to be real time operating systems. They were designed to keep the mouse moving and the network happening. Uh, those are the priorities, uh, your app, uh, being responsive within a millisecond is different. So what you actually do if you need that. Perfect, perfect, perfect world. You undershoot first. So you delay, let's say like, uh, 900 milliseconds and then you hot spin. Inside of a loop. You don't give your time, slice back over to the operating system. Again, you request a higher thread priority, but you do it generously. So you, you kind of like task sleep almost up to the point where you need to be woken up. Then you wake up and then you hot spin in a loop, checking the time on every loop, and then you can nail. Pretty much we'll call it tens of microseconds of accuracy. You can probably accomplish that. [00:17:21] James: Yeah. Yeah. That makes, that makes some sense. It it's all tricky. Cuz when I, when I looked at it, I implemented the timer. I did the poll request. I sent out the tweet about how you fix my application. Cuz now the CPU zero, we use the tools. Frank, we were sending photos back and forth and then. I things. [00:17:39] Frank: Yeah, I have to say, I, I, I just kept saying Jay is over there. Like send me pictures, just send me pictures because a picture's worth a thousand words. Like I kept saying, like, you kept telling me what the peaks, the values were like 13% or 15%. And I'm like, James, I really don't care what the value is. I'm just looking at the shape. Like the shape tells you everything. The, the app should be sitting at zero. We've talked about a hundred times [00:18:01] James: and in the. I'll try to put that in the show notes too, is I sent photos and I was like with 300 milliseconds, it's like plateaus with 800 milliseconds. It's like, uh, little peaks, still kind of running a much for it. With the timer. It was near a trace. It was just the Minit tiniest bumps, running elegantly, which it should do. And then. Mr. Anthony Weiser from the, I was [00:18:23] Frank: done done. I thought it was solved. I was like, oh, you know what? We solved James' bug. He can go on to become the billionaire. We're all waiting for him to become, and life is good. And then Twitter kicked in someone smarter than me showed up on Twitter. [00:18:37] James: someone now here's the cool thing about Anthony's like Anthony looked at the. And I appreciate it because, um, he was like, I don't understand why this change would make any sense. It's the same code. Like something else must be going on. And sure enough, there was something else going on because Frank, I overengineered. [00:18:58] Frank: You weirdly engineered. Yeah. You overengineered you over [00:19:02] James: overengineered over optimized my code cuz here was the problem. Frank, in my mind, let [00:19:08] Frank: me, can I try to explain it? Can I try to explain it? Yeah, go for it. This is what I'm guessing was going through your head and then you can correct me here. So you did identify, you're getting these weird hiccups in OBS basically because of the, a wasting issue I mentioned before, um, But then you put in this wise idea of sampling three times a second. So 300. So you're Bing, Bing, Bing, Bing, instead of once a second. And then you're like, but that's wasteful. You know what two outta three times that number's not changing, you know what, I'm gonna be an efficient programmer. I'm gonna over optimize the software that needs zero optimization. It's doing nothing, but I'm gonna optimize it anyway, because I haven't run a profiler and I have no idea what's going on here. So sorry that, that, that last part was mean. I'm sorry. true. And so I'm gonna put in some clever. Cash invalidation logic. And you know what? Programmers are really good at James, anything except cash invalidation. We stink at it. We stink at detecting data changes. That's why we have 8 million MVM frameworks and swift du UIs and all that junk. Cuz we stink at this stuff. And so you handwrote some, oh, I'm oversampling. Therefore I don't wanna do any work when I am oversampling, but I need to detect when I'm not oversampling, even though I know I'm over sampling. And he put some code in there and that code had a bug. How, how close was I that code? [00:20:33] James: Yeah, had a, had a, had a bug. [00:20:36] Frank: Correct. I had a bug. Can you, can you describe that bug now? The bug cause in general, it's a good idea. Sorry. [00:20:42] James: In general, I was like, Hey, this is happening in the loop in the loop in the while. And, um, not a do, not a do while, but a wow. Um, Loop, uh, in general. So I'm looking and I'm running this puppy and I, I, I look at the previous time and I see if it's the same as the current time. So Hey, you know, check the seconds, minutes, hours, and days, and everything's hopefully good. And if it's the same, just, [00:21:16] Frank: just continue. You don't even do such fine words. Just con now define what does just continue mean in this instance? [00:21:25] James: Well, Frank that's that in layers. And that, that, that, that Frank is the issue because if I was to have do wow and I put the weight first, the problem is the weight. The, a weight delay is at the very bottom at the bottom, at the bottom. And you know what? Doesn't get hit when you continue the bottom. Anything else afterwards, by the way, [00:21:53] Frank: So can I just say yes, he created in an app that needs to display once a second needs to write to the disc. Once a second, he was in a hot loop, like a Fullon spinning hot loop. Uh, the CPU had no chance to breathe. Mm-hmm because it was checking the date time. And if the seconds hadn't changed, which, you know, it takes about one second for the seconds to change. it has the spin in its hot loop and that's where all your CPUs were going. So whoever, uh, emailed you there. Well, a, we owe them for two shows worth of content, but B that was a good catch on their part. [00:22:31] James: Yep. So that, that's what happened is I was sitting there and sure enough, I, yeah. And that's why we saw that it did spike down because eventually. The time did change and it did win my. 300 milliseconds and then it ran again for a full second or about 700 milli everyone. Yeah. [00:22:49] Frank: Everyone. It was so confusing. Okay. So we're we're okay. It should be a peak and then I should go to zero, but we were seeing the opposite. It was high CPU and then it would peak down to zero and I'm like, What is going on with this code only now, does it finally make sense? Because it was stuck in that hot loop until the seconds actually did change. So it was literally doing the opposite of what it should have been doing. uh, you, you would think pizza software, like this would just be trivial, but man, it's funny how you can just get yourself into these bugs. [00:23:20] James: It's. Yeah. It's one of those things where you're just like, when you see it, you're like, why did I [00:23:26] Frank: do that? What did they say? The best bugs are? The ones that like, at first you're like, there's no way there's a bug here. And they're like, well, maybe there's a bug here. And then you find the bug and you're like, how did this ever work at all? Like, how did any of this work? I love those books. [00:23:42] James: It's it's true. It doesn't make literally any sense at all. It's it's quite amazing. Absolutely spectacular in general. So what I did. Is I use the power of try finally, Frank [00:23:58] Frank: yawn. so lame. So lame. It, it, it's a good idea. I think you should still catch your exception here. You don't need to be throwing exceptions inside of a loop, but, um, yeah. So I'm assuming you put your test stock delay inside of the finally, which means no matter how you screw up and exit this function, it's gonna do its. [00:24:19] James: That is correct. Yeah. And for you, Frank, I will put in the catch and I'll just log it to disk and I'll do anything just so you're happy [00:24:27] Frank: I'm doing it right now. I, I just UI apps. Shouldn't crash everyone. It's just a rule. Um, yeah. I, you know what I gotta say. I'm. Still prefer the timer, uh, for that all the reasons I mentioned previously, I think that although tasks are plenty good at being in a loop, they were certainly designed to be okay in that scenario with a task dot delay, it's fine. They even have that, uh, long running flag. I believe you're supposed to send to the factory to let it know that you're creating a task that runs for a long time. And I am oh, Good good for you. Um, so it is designed for all this. It's fine, but me, myself and I, uh, when given a simple thing that's obviously made for timers, I [00:25:09] James: use timers so here's so here's, so this solves a problem. Try, you know, the try. So, Anthony, thank you. You did catch my bra problem and I got it and I got it working and then I did another optimization cause I was like, you know what? I've solved. One overengineer problem. How can I overengineer this other thing? because Frank told me that I'm gonna get this drift in time in general. Yeah. So what I'm doing, which I don't need to do at all, this is completely stupid, but I'm, I'm seeing how long it takes to run the, the method, basically. Yeah. Yeah. I'm probably not even doing it. Correct. But what I end up doing is I say at the, at the end, take a look at the current ticks and right before you test that delay, compare yourself to the current ticks now. And I have to do a time span from ticks, grab the milliseconds. Yeah. And then I take that 1000 millisecond wait, and I subtract however long it takes in general, which by the way is about three milliseconds, which means it really doesn't actually matter in any sense, but maybe. But I, I, I wanted to fix the sliding time delay issue that potentially could come up in general. And you had a fancy name for that? [00:26:26] Frank: Yeah. Oh, um, I don't know which one I use because there's a lot of names for all this stuff. Uh, but you you're, you have an out phase signal and your phase is moving that's because you have an unforeseen yeah. Delay every time. So you, you are move your phase angle with respect to the actual signal. The actual signal is the real time clock on the PC. Yes. Which has a second counter going. Tick tick. You wanna be in sync with that. You are not in sync with that, but worse with your little drift, your out of syncness changed randomly so on multiple angles, you're outta sync. Now the problem is okay. So that's a good idea. Uh, we do that in controls all the time to compensate for how long, the control loop versus all that other stuff. You found that your loop is only taking three milliseconds, which makes perfect sense. It'ss not doing very much. The problem is the scheduler latency, the task scheduler latency. I guarantee you is much higher than three milliseconds. So you should also be measuring that you should be measuring. When I tell it 800 milliseconds, how long. Actually take for, to come back to me and that will tell you the latency of the operating system. And that's gonna be somewhere more between 10 milliseconds and 20 milliseconds. And that does not matter how good your computer is. The world's fastest, super computer will give you the same answers. It's baked into the operating systems, the way the scheduler works with the operating systems. One more time, not real time operating systems. So , uh, you're always gonna have that kind of problem. All of that said, um, probably won't notice too much in the app, as long as you're compensating for one or the other, you really should be compensating for both. You are compensating for what we would call the bandwidth of the system, but you need to be compensating for the latency of the system. Also, you always have to compensate for both in, uh, a time based system. Or you could just switch over to timers [00:28:31] James: or, or Frank, which is what I may do is you told me what, if you, now that my code is fixed, technically it's fixed Frank mm-hmm what if I just updated? And I only awaited, or I did a delay of, instead of every second, every 100 millisecond. [00:28:55] Frank: yeah, that one, I like a lot more. And this one will, this one is for the OCD. People like me out there. uh, in the upper right of my Mac. I have the system time, but I have it showing the seconds. So I see like 14, 15. I know exactly where the computers clock. Is app. And if I have any kind of time app and it's clock is not in sync with the real time clock of the operating system, it drives me a little bit batty. And since, um, your algorithm is basically doing nothing, it takes three millisecond and a good chunk of that is probably it just waking up. Yes. Uh, I really do believe that you should be, uh, sampling at the higher frequency, uh, 10 times a second. Probably definitely overkill, but, um, that would visually put you in sync with the system clock. I, I mention all of this because it's always been a frustration of mine basically with POS and even, um, VMs or whatever it was that windows copied, whatever the NT kernel is based on. None of them give user mode software a way to synchronize with the real time clock. There are some deep down ugly driver things where you can ask for a callback at very specific times, according to the synchronized clock. And I have to make a distinction here because this is very different from video games, which need very accurate time measurements, but they don't need to be synchronized with the system clock. It just doesn't matter. You know, most software does not need to be synchronized with the system clock in your case. I think it would be nice uh, but unfortunately the operating systems don't really give you a nice way to do this.net. Definitely. Doesn't give you a nice way to do this. You can do it through a multitude of hacks. None of those would ever work on iOS or anything like that. So don't even bother instead sample 10 times a second, and try to get the, uh, try to get the [00:30:53] James: transition. So I have implemented this. And what I do is I write to counsel every, every time I await. So I wanna make sure that I should see 10 awaits in the time. And then I do another one that says, right, like how often am I writing to the disc? And that should be once every second. Right. So ideally it should be like time to time. Oh, it changed. Boom. And let me tell you, Frank, now that we've fixed now, what, now that I know how to profile with diagnostic tools and we've applied, Anthony's fix and we've applied your fix. Implements the once every, you know, a hundred milliseconds, the CPU usage, Frank is zero and it is updating elegantly and only writing to disk once every second. That's the most important part is only writing to disk every second while still being performant. Amazing. [00:31:47] Frank: Yeah. Yep, yep, yep. Yeah. You really don't wanna, uh, beat on the disc. There. I, it was definitely worse in the old days when you had spinning disc, but you still don't want to be running to the disc that often even databases try not to write to the disc that often. So good for you. Good for you. And even the, the disc, right. Doesn't even count as CPU time. Usually that doesn't show up in the profiles. So that's doubly ex excellent. They're not counting there the great way. If you really wanna know how good your display is going, um, log to a different file or a pen to the file, run it for a couple days and make sure you never lose a. Like that's what a, I know would have to do. You would actually have to take a trace for a few days and demonstrate, you know, run the experiment. Am I ever missing a second? Yeah. Now in your case, I, I think it's okay if you miss one second out of. You know, a thousand, maybe one out of a hundred. I don't know what your actual chances are gonna be, but you're, you're still gonna have aliasing no, I take that back. If you're sampling at 10 Hertz, you're fine. You're fine. You're gonna catch every one of those seconds. It's perfect. James, ship it. [00:32:56] James: Now the, the, the reason I will, I will say this and we'll kind of close outta here that I decided to go with this route versus the timer is for some reason, I don't know if it's some threading thing or if it's something else. I was getting it where OBS was blanking out the, the timer. So I don't know there's something happening there and I'm not sure what's up where in this one, it seems to be smoother. But again, OBS is looking at a file and so many things and locks and other things can happen in the monitoring. I don't know what happened. Let me ask you one more question. Frank mm-hmm system dot diagnostics dot debug dot right line. That will only write stuff to the, the. If it's in debug, correct. [00:33:40] Frank: Yes. Well, I, if the debug flag is present the capital DBU flag. Oh, it, it really is that simple. Um, if you look at the API, it has an attribute on it. And that attribute says, um, debug, conditional, that attribute means the capital debug, um, compiler flag needs to be set. So it's not like, what is your build setting? It's really, what is the capitals? What is the. [00:34:08] James: Where, where, what, there's a conditional attribute that you can add to methods, right? What? Oh, [00:34:14] Frank: I'm sorry. Welcome to.net. 1.0 yeah, baby. Wow. This is, yeah. Hey, you got partial methods. Let me tell you about conditional methods. These are even more complicated. Yeah. So any ape, any. Method, you have, you can put the conditional attribute on and you give it one of those. Um, what do, why am I blanking on the, the defines the defined thing? Yeah. The, if things, you know, you gave it one of those, if that, if things not defined, then that. All calls to that function disappear. Wow. So it has the return void. I'm pretty sure it has the return void. It does. Yeah. Um, and I don't remember if the, I think the argument evaluation is disabled also. Wow. So be careful with it. Um, but. The whole idea is so that you don't have to put a million if deaths throughout your code. Wow. And this is gonna come up really importantly in, um, Maui, uh, uh, cross platform programming, because this is a good way to just say, this function only exists on, uh, Android or something [00:35:17] James: like that. Wow. This is amazing. Um, Wow. [00:35:24] Frank: Okay. Yeah. [00:35:24] James: That's, that's a powerful one. that's a super powerful one. I love it. Um, I just learned about this and it's cool because it it's a CISM CISM about right. The right line council, right line that that'll always output it to, to desk. So, [00:35:39] Frank: yeah. And on iOS that uses NS. [00:35:42] James: Yeah. Yeah. All right. Cool. Um, I've now shipped my other update that has all the fixes with the sliding one millisecond or one second, I'm gonna do another update, you know, which, you know, we'll do the, this one, but I'll, I'll teach more, seek more bugs out, but sure enough, we fixed the problem. We've diagnosed the problem and thanks to. At least one of my Twitter follows. I don't know if Amy's a listener, but thank you if you are, and thanks to you, Frank, for helping me solve this and thanks to everyone for tuning in this has been super fun and we like literally solved the problem. Now here's the thing. It has been a problem for at least. Four to five months and no one's noticed it. Yeah. So there's that. So [00:36:24] Frank: I, I, I blame slack and all the terrible chromium software that we all run. Like we all just look at our idle CPU and we're like, ah, it's under 50%. Good enough. Good. Um, it's kind of pathetic. Like I'm, I'm looking at my idol CPU right now and there's three apps taking out 10%. It's it's not good. You know, computers have gotten so fast. We programmers are allowed to get away with some laziness here. Yeah. Look, Google CR. Oh, okay. Well we're recording a podcast. 35% but there's another like 13% of Chrome just sitting there doing nothing. It's called the Chrome background. Do nothing service and it's 13% Dropbox is taking up 10% right now doing absolutely nothing. I'm not doing anything with files right now. So all that's to say is, uh, use that visual studio profiler thing. It's awesome. Your app is at zero all the time, please. [00:37:23] James: Yeah, so good. All right. Well, thanks everyone for tuning in. Thanks to you, Frank. Thanks for everybody. Who helped out here. I super appreciate it, but that is gonna do it for this overly optimized episode of merge conflict. So until next time, I'm James Bonta, Magna, and [00:37:37] Frank: I'm Frank Kruger. Thanks for listening.