And welcome to Figments, the Power of Imagination, season four, arbitrarily determined episode one, well, it's the first one, my arbitrary season four. And I'm happy to be with you and to chat with you about air superiority, imagining air superiority. That's an important topic that's come up a lot in commentary on the Russian misadventure in the Ukraine. And sadly, most of the folks who are talking about it don't know what they're saying or what they're talking about. It's a complex topic. So, you know, that kind of kind of irritating. So I've got to give you a quick viewer warning here, folks. Quick viewer advisory, your host is irritated. I am irritated. My wife, Ollie Hunter told me the other day that it seems like I like to be irritated. I look for things to irritate me, but that pissed me off. No, it didn't really. She never makes me mad. But this does irritate me because the folks are talking about a very important topic, extraordinarily relevant to American military operations in the future. And they're giving a hand wave like it's an on-off switch. You either have air superiority or you don't. And it isn't that simple. Now, this whole discussion of air superiority started with an even more annoying discussion of no-fly zones, the topic of my opening rant, because people really don't know what they're talking about, no-fly zones, including some who should not. On the right side of that map there are two no-fly zones established in Iraq and I patrolled both of them, one in the F-15, the other in the F-16 up there. No-fly zones, folks, are not an instrument of war. The discussion should stop there. If anything else were to be said about no-fly zones or other military matters, it would be to say less, shut up, keep it secret. Don't make it a podium discussion in the daily press conference of anybody. I realize we have to engage with media in the modern military, but the no-fly zone discussion is ridiculous because it's not an instrument of warfare. It's in essence a sanction and post-conflict. Now, it could be a pause in a conflict of truce or a ceasefire, or it might be at the end of the conflict because it was after Desert Storm in Iraq. These are the no-fly zones that existed between the end of Desert Storm in the beginning of Iraqi freedom in 2000, from 1991 to 2003. So they require an official mandate, by the way. You don't just make them up. You don't just say, okay, that's a no-fly zone for you and a no-fly zone for you and an Oprah Winfrey sort of a way. Everybody doesn't get a no-fly zone. And that mandate usually comes from the United Nations, the United Nations Security Council in the form of a resolution. Who's the chairman? Who's the chair of the UNSC, the United Nations Security Council right now? Sadly, it's Russia. So that's probably not happening. This is a discussion that diverted too much attention of our national leadership and of the public and I find really irritating. There were other options and those were not discussed, nor do they appear to have been used, but that's neither here nor there. So having said that, let's talk about no-fly zones. And I'll get over my irritation that I think that the, or let's talk about air superiority, that the depth of understanding of air superiority and all the elements of it appears to be about as deep, maybe five, 100 to the millimeter, the thickness of a piece of paper that you can print a snarky tweet or a sanctimonious meme on. Folks really don't understand it. There's a long history since the beginning of air power, World War I, to now in the concept of air superiority. And it's a fundamental enabler. And that's what I'd really like our viewers to know, many of you are not military experts. You might just tune in to see what other interesting people I know are kind of funny stories I might have for you, but you all should think about this, all American citizens should give some thought to what we need to be successful in employing our armed forces, ideally for defense, but if necessary in conflict in the coming years. Air superiority is the great enabler. For United States forces, for reasons I'll discuss in a bit, it has become an assumption almost looked at as a birthright. We're going to have air superiority. And it's not that simple when Ukraine should further illustrate that we can't make that assumption. And it's invalid and dangerous. And we have to do our best to have the capability to achieve air superiority, ideally to deter conflict, but if necessary to be successful in conflict. So, what is air superiority? I should know, because I was an air superiority fighter pilot for a long time, a long part of my career. That's me in my initial checkout class in the F-15 in 1981, and on the tail of a F-15 at Osan Air Base sitting alert to keep the North Koreans North and protect the South Koreans South. And so I did that for almost 2000 hours. And as I said, I flew over Iraq and later commanded a wing in the only war where the sole direct application of military power came from the air. And I would submit that we won. And I learned a lot about that, about air superiority in that. I'll talk about that in a bit. But you need a definition if you're going to understand air superiority. So, since this is in NATO's backyard, East Yard, I'm not sure what you call it. Let's look at a NATO relevant definition. Air superiority is a measure of dominance of the air power hat that one side's air power has over another as you see on the screen during a military campaign, which we're seeing unfortunately, Ukraine. And in the NATO glossary, they say that the degree of dominance in battle, in the air battle of one force over another permits the conduct of operations by the other, by everybody else, land air, sea. And that's key. It's not the end all be all, but without it in modern warfare against a committed and capable adversary, you're in big trouble. And there's good evidence over and on the terrain of Ukraine that reinforces that. And the idea is that you want to be able to use your elements of military power at the time and place of your choosing without prohibitive interference. So if you take anything away from the definition of air power that I've just given you of air superiority that I've just given you, it's that without prohibitive interference. Because that's a euphemism for casualties folks. That's how much are you willing to sacrifice to achieve your military objectives? And the measure of air superiority that one side has over the other is in large, to a large degree, the determinant of how many casualties you have. And that's blood and treasure airplanes but more importantly people. We haven't had to spend much lately and we have gotten the idea that we have a birthright to air superiority, not true. So let's go back only to World War II. World War I is relevant, but I only have 30 minutes here on figments, the bar of imagination. And I was not yet on active duty in World War I or several of the others, but there is relevant stuff there. First talking about World War II, we were able, well, let's look across, not just us, not just allies, but look at the impact of air superiority in World War II. In Europe, the failure to achieve air superiority over England sported Hitler's ambitions to invade the UK. He thought he could, he didn't. Air superiority to a sufficient degree enabled the massive landing at D-Day. Imagine if in addition, all of the other threats that our landing forces faced, they were under continuous attack by German aircraft. There were some attacks, not enough to deter it. And it enabled the D-Day invasion. There was no question about that. In the Pacific, the air superiority was achieved to a degree that allowed us to launch the nuclear attacks Hiroshima and Nagasaki. You can view those as you want, but the truth is they happen. And the truth is they were critical to ending the war short of an invasion of the Japanese main islands. Again, that doesn't mean that it was free. The air superiority, such as it was, came at the cost of 50 over 50,000 casualties in the US Army Air Forces alone, 50,000 casualties. And that was suitable to fall within the, I guess if it's not prohibitive, prohibited interference. It wasn't prohibitive interference because the conflict was so massive and important and the threat so existential to the United States that we were willing to spend those lives, 50,000 sharements and many soldiers and sailors just trying to put a price tag on air superiority for you in that case. And we were never completely, we never had complete domination of the skies. We had enough to allow us to do what we needed to do. Sometimes on a very local level, the Japanese had local air superiority over the island of Oahu on December 7th, 1941. They didn't sustain it and they didn't need to sustain it. They needed to dominate the skies for about an hour and a half to achieve most of their tickets. In April of 1942, the US achieved an odd bit, an unusual bit of air superiority when the duly little raid occurred and we launched some B-25s off an aircraft carrier for surprise attack on the Japanese main islands. And that local air superiority was very brief and very local, but it was good enough to deliver very significant blow, not in a military sense, but in a psychological sense and a strategic sense to the Japanese military. So it doesn't mean you own the skies. It doesn't mean you're not going to lose any aircraft or pilots. It means you can do what you want and it enables the land and sea forces, not just the air forces. That's air superiority for your two style. In the Korean War, we rapidly established air superiority over friendly forces and we had sufficient air superiority over enemy territory to support our troops and to conduct strategic bombing. That's a topic that the strategic bombing in North Korea is a topic I'd like to address in detail. It's a very difficult tragic episode not to cover, but not today, but we had sufficient air superiority to succeed within our cost constraints to go back to that notion without prohibitive interference. It was good enough. An interesting point about Korea that is historic, that is relevant to the current conflict in Ukraine is that one of the biggest challenges for maintaining our desire for necessary level of air superiority during the Korean War was the use of sanctuary airfields in China. Just across the border near Sinai-Ju and Dundong were some dirt airstrips, dirt fields with over 400 meg-15 jet fighters that would fly out of China and largely be able to go back to China safely and hide there. They were flown by some North Korean pilots, but many Chinese and a lot of Russian pilots. That's right, Russian pilots. We could have been a little more imaginative in thinking about solutions to make that the Russian Air Force's application of air power against Ukraine difficult, I think, and we could have used that model. Too late for that now. Maybe it was discussed. I wasn't part of those discussions. I'm not sure. But the sanctuary airfields did present a real challenge and while we had an acceptable ability to conduct military operations, and we continued to lose aircraft up to the end of the war to these MIGs operating out of sanctuaries, we were very successful in providing air superiority over our friendly forces, our friendly ground forces. In fact, 1953 is the last time a U.S. soldier was bombed by an enemy aircraft killed by an enemy air attack, 1953. And that's in large measure why I say it's so tempting to think of air superiority as a birthright, as a given, as a constant. And that's not necessarily the case. So on to Vietnam. Vietnam, once again, sort of similar to Korea. We had air superiority most of the time over friendly forces against North Vietnam over their territory, not so much. And the air superiority that we achieved over friendly forces didn't protect our helicopters from AAA, anti-aircraft artillery, flak guns up to 85 millimeters, so pretty big guns and even a machine gun. During the Vietnam War, the U.S. lost over 10,000 aircraft. 10,000 aircraft. So as I've said, air superiority is not as simple as hand waving, we own the sky. It's a tough grinding business that has to be dealt with throughout the course of the conflict. And Vietnam has a clear instance in that. So we lost over 10,000 aircraft, including helicopters and drones. Drones were used there, but not as we see them used today. The loss rate was about four tenths of an aircraft per 1,000 stories. It's hard to lose four tenths of an aircraft, four tenths of an aircraft, but you know what I mean there. Converse, or in comparison, we lost two aircraft for 1,000 stories during the Korean War and almost 10 per 1,000 stories in World War II. So we were getting better, right? Right. But it wasn't really that good. And in our air-to-air fights against North Vietnamese MiGs and in evading and defeating surface-to-air missiles, which made their debut in the Vietnam War as a significant force, we were not successful at all. And that inspired a significant investment in real air superiority capability, in especially the F-15, but also the F-14 and the F-16 as air superiority aircraft in the US took the lessons of Vietnam, applied them and built some very capable airplanes. A couple of those were used in both the Arab-Israeli conflicts and the Iran-Iraq war. I'm not going to talk about those in the interest of time because I wanna talk about the illusionary nature of our post-Vietnam experience. And that this includes all of our conflicts from Panama to Grenada to Iraq to Kosovo slash Serbia to Iraq to Afghanistan to Syria, where we have basically total air superiority and every one of those. That's not solely because we had the best stuff, the best aircraft, the best pilots, the best training, the best missiles, but it's also because we never ran into an adversary that had the key requirements, a combination of capability and commitment to oppose us in the year. It worked out very well. In my own experience, I've been over enemy territory in Serbia at the moment where as a one-star wing commander I decided we had achieved total air superiority. We were attacking a target at night and the weather was bad and we flexed to another target. And the weather was bad there.  We did that without opposition. We had air superiority, reasonably capable but not fully committed adversary. That's not necessarily how it's gonna be in the future and we need to learn from the experience of Russia in the Ukraine and plan accordingly. So let me take a quick breath and mention that in two weeks I'm going to have Jim Hayth, the CEO of Spirit of America, a nonprofit, a very unique nonprofit, a non-governmental organization that's doing some wonderful work for supporting the Department of Defense and the State Department in their efforts to support Ukraine. Jim will come talk to me about how he founded Spirit of America, what they're doing now and what their motivation is, really what's different about Spirit of America because it's a very unique nonprofit and I'm proud to be on their board of advisors. Please note the length there. They can use your help. They're doing some great work. Go to their website spiritofamerica.org. The donate button will be right there in front of you and I hope you'll support them. Either before or after you see Jim in a couple of weeks. Okay, so let's get on to what we need to learn from Russia's misadventures in Iraq. As I said, we have this illusionary sense of air superiority. There's a beautiful F-15, I've thrown that jet, that particular jet as the operations group commanders, the Colonel lying the Air Force base and the FF first fighter wing. The F-15 is 104 to zero, is its combat record in air to air combat. Think about that, 104 to zero, never been shot down by another. It's a dominating airplane, right? What about next time? As I said, we haven't faced, it's not that it's not a great airplane. It's not that we don't have great and well-trained pilots, we do, but we have not faced a modern, capable and committed adversary. Russia is facing that, much smaller, Ukraine is much smaller, not as well equipped as they are, but they're facing it and they're facing it in the complexity of a 21st century warfare environment. And it's not just the aircraft and its guns and missiles that you're fighting. It's the surface-tier missiles, the advanced surface-tier missiles, like the S-300, by the way, the S-300 surface-tier missile and older Soviet-era missile, there was a rumor that those would be introduced into Kosovo during the air war over Serbia. My assessment as a combat commander was that we would lose five airplanes in a snap of a finger, if that was introduced and not detected and that would seriously impede our operations. It's still very capable and game-changing and not yet really faced until this experience over Ukraine. You've got cyber capabilities that the Russians have and the Ukraine and then a expanded use of drones. And I suspect many of you've seen the footage of the Ukrainian drones attacking Russian armor. They're not big, they're not expensive. Some of them are home hobby drones. Getting air superiority is really complex so we should learn that. There have been lots of losses on both sides. I tried to sort through and be ready to give you a good assessment of what's happened in the air. I can't because I don't trust what I see in the internet. It's gonna take a long time to get to the real who-shout-who, how much of it. But there have been a lot of losses and there's a pretty credible report that one of the most advanced Soviet fighters, Sups, that was a Freudian slip, folks. One of the most advanced Russian fighters, a Su 35 S was shot down. There's some pretty compelling pictures of wreckage and of the captured Russian pilot. So lots of losses in a big war, not what we've experienced before. Size matters.  A lot of opportunity options for access and for hiding, camouflaging, moving things much bigger than Kosovo. It's about the size of Texas. Iraq was pretty big but when I went to war there on the ground, one of the first things that struck me in the planning was the size but it was only the size of California. Ukraine's much bigger, the bigger the operation, the more complex and the broader demands you have for surveillance, for intelligence and for the ability to be present to maintain air superiority as needed to let your forces do what they choose to do. We've learned that Russia is not as capable as many expected. They've got some very good equipment, very capable aircraft and missiles but they're landing air forces, not as capable as we expected. We can't expect that from China. And why do I mention China? Because there are pacing challenge. They are strategically, there are most likely big problems. I don't advocate war with China at all. I advocate the opposite and that means I'm for deterrence, not confrontation but the Chinese are gonna learn from what's happened in over Ukraine, what's happened with the Russians, what their losses have been, what's worked and what hasn't and we have to learn as well. What should we learn? We should learn that we must understand what they need to go back to my definition. What is the measure of prohibitive interference? What are we willing to sacrifice to achieve our military aims? Because the next time we're involved in our own conflict, I believe it's highly more likely to look like the warfare in Ukraine than what we've seen in Iraq, Afghanistan and elsewhere in recent years.  So what are we willing to sacrifice? A, how do we limit that sacrifice? What capabilities do we need? And I'm an air superiority fighter pilot. I believe in the F-15, the F-22 in particular, we need those capabilities. They're expensive, but if we don't invest in we're not going to deter and if we wind up forced into a fight and I pray we don't, then we're going to have losses that may cost us more than we're willing to sacrifice and allow folks who don't see the world as a free and open place. May allow them to succeed. I don't think we want that. So that is a start on a conversation about air superiority because it is complex. I think it's a topic that needs to be addressed and much better understood than it has been in the media. So what would Fig do? Here's my advice to you. Faithful figments viewers, don't be naive about the requirement for deterrence or about the cost of rule, especially the cost of rule and encourage your elected representatives to invest in deterrence and be ready. Next thing I advise comes from my irritation factor. As I mentioned, think deeper than tweets and memes. They don't explain anything. They should start you searching and reading and wondering. And then finally, please consider donating to both Spirit of America for their efforts supporting Ukraine and actually supporting the US efforts to support Ukraine and of course, think tech-wide. Our hosts for this, you can find my previous figments on reality at that barcode and all of the playlist for figments, our imagination at the barcode on your left. So again, thanks to figments or thanks to think tech-wide. Thanks for tuning in, folks. I'll look forward to your comments. Please drop me a note at info at phase-one.com and I will see you in two weeks on figments, the power of imagination. Aloha. Thank you so much for watching Think Tech Hawaii. If you like what we do, please like us and click the subscribe button on YouTube and the follow button on Vimeo. You can also follow us on Facebook, Instagram, Twitter and LinkedIn and donate to us at thinktechhawaii.com. Mahalo.


Hello, everyone. My name is Kat. Thanks for coming to my talk. I'm a software developer. I've been doing PHP for give or take seven years. I also read like Golang. I do a bit of Java at work. I do a tiny bit of Ruby, a little bit of Bash. So I kind of do a bit of everything. And I quite like to pick and mix. I work for a company called Brightprol, and they're in Bristol. I've lived in Bristol for the last almost a decade now. I'm from Warsaw in Poland originally, so hence my slightly different Twitter handle. And today I want to talk to you about optimizing performance. As developers, when we start working on something and when we're given a task, then we usually probably like to go off and do a bit of planning. So you either sit down and you work out what you want to do, or maybe you have a proper planning, like agile style with the sticky notes on the whiteboard.  And maybe your continuous integration pipeline passes as well. So we're good to go to production, right? Well, where is performance? Most of us don't really consider performance day to day when we're working on stuff. And that's a very typical scenario. And you can't really blame developers for that because analyzing performance is hard. It can be tedious. And not many people know how to get started with it. I mean, we all know the theory of what is it about, but how do you actually go about it? How do you actually do it? So today, I thought I'll show you a little example of how you can go about it. I'm by no means an expert, but this is just me sharing what I've learned when I first had to do it for work. So let's start with the first things first. Why should you care about performance? I'm not going to spend too much time on this because hopefully it's obvious to most people. In case it's not obvious, how about this? Fast is better than slow, duh. Memory efficient is good. Saving money is good because you may run your app on less servers if they need less memory. Running out of memory in production is bad. And suddenly running out of memory in production is really bad. I mean, probably some of you have been there. I've been there. Or maybe you're just forced to look at performance once. Maybe one of your graphs starts looking like one of these. So the top one, it shows memory. That's a typical memory leak up there.  Or maybe you had one of those graphs at the bottom with some spikes in here, so some requests taking 30 seconds or longer and you're wondering why and what's going on in here. Or maybe you had the dreaded fatal error, a loud memory size exhausted. Or maybe you just want to have a look inside the memory and just figure out what's inside your code when you're running it. So that kind of covers the whys. We all have to deal with it at some point in our lives. In terms of when you should look at performance optimization, you should kind of be looking at it every step of the way, like every stage of the software development lifecycle, really. So you should be looking at it in dev when you're writing code or maybe you're asked to analyze an existing app.  So after you've done your unit test and your general testing, you might have some kind of performance testing suite that will run and then see if you've improved or maybe degraded performance. And then even after you're done working on your software, you should still keep an eye on it over time because sometimes issues only come out a bit later because maybe the memory leak is quite small, so you only notice it after some time. So you should monitor your production environment to spot any issues and then you can just tackle them right away. So that covers the when and the why. What about the what to optimize? I mean, we all kind of have a general idea. When I look at problems, I like to start with this question. Do I really need to do this? And that's something that it's so easy to forget because we're all just like jumping in and just start micro-optimizing right away. And it is really easy to forget that it is important to take the step back and first of all, ask yourself, is the thing that I'm looking at, do I actually need to do it? Like is this redundant code? Maybe it's dead code. Maybe I don't need to do it more than once because of course doing it faster is better but not doing anything in the first place is the best kind of optimization you can make. So think about that first. And that applies to, like I said, dead code, maybe something that you're doing multiple times instead of once. So kind of be lazy to start with. If you don't need to optimize, if you can just get rid of something and do that, in terms of the general things, most of us have a good idea for what we should look for. So we want our programs to run faster and consume less memory. So we want our garbage collection pauses short and infrequent and very efficient. So we know that we should probably measure memory usage and execution time. In addition to that, you should probably try and establish your maximum, minimum, and average values because it is important to know what your app's requirements are. And your CIS ads and your DevOps will love you for that information. And very often, developers just can't answer that question when they're asked, like, you know, what kind of server does your app need? You know, we just like to chuck stuff over and go, well, can you just deploy that now? And then if you can actually give your CIS ads or your DevOps some kind of information for like, I'm expecting this app to require this amount of memory on average, they'll love you for that.   So this is my very, there's a bit of caveat to this and this is my very unscientific graph to try and explain that. So we have three aspects. We have memory, memory, time, and code. And we're all kind of aiming for that zero point here, that unicorn, where we've got as little memory as we can, it's just the code that we need and as little times as possible. But it is important that that's, it's important to keep in mind that that zero unicorn point is, it's not really something that you should necessarily aim towards. So optimizing performance is more of a balancing act because it does come at a cost and the cost is readability of your code and maintaining ability. People sometimes just go crazy and they will write really weird code just because in theory it performs faster but it makes no sense to anybody else and even them reading that code three months later they're like, I don't know what I meant here. So it is important to keep in mind that you do sometimes compromise readability if you want to do things faster. So you shouldn't necessarily aim for that zero point, like a die-hard kind of thing. You should just stop at a sensible point. Something that is good enough for production is probably good to stop at. So don't necessarily expect to get to the unicorn. In terms of, again, the what, there are a few sort of typical things that we probably already know when we think about performance. We've got the memory leaks, which is a potential issue. So the amount of memory your program uses may be increasing over time or maybe it is that your app is just using more memory and it could use a bit less and you just want to make it use less memory. And that might be caused by leftover open file handles, your overflowing buffers, that kind of thing. Timeouts, so your app might just be stuck waiting on something and you don't know why or what it's waiting for. Concurrency, if your program is concurrent, it's not something that you typically do in PHP, but you can. So if your PHP is concurrent and you've got all the lovely issues that come with concurrency, like race conditions and threat safety and dead logs and live logs, so that's something to watch out for. The normal redundancy and inefficiency, so doing something more than once and also dead code and unused libraries. And you might think, well, that's not really a big issue, but it will affect, for example, your deployment speed, your build step time, your compilation speed, because if you're just pulling some kind of libraries that you don't really use, then you're still taking that time to do it and then you're not using it. So even stuff like build time might matter to you. And there's obviously a lot more issues around your server config, where you run your app, how you split it, but I'm not gonna focus on that today. So you could do things like opcache settings, optimizations, you could tweak your Nginx and Apache settings and that kind of thing, but I just wanted to focus today on specifically the code issues that you might have. When you start Googling, you might find some sane advice on the internet, and these are what I would say just general good coding habits, like sort of the ones, the two ones at the top and the sane ones. So it's things like, if you have a condition in your for loop, don't evaluate that every time. If you're doing something, if you have a count in there or something, don't evaluate that every time you loop through the function, do that beforehand and then just use a constant in the loop body or in the loop condition. That's pretty sensible. Watch out for DB queries. That's kind of very common if you've got really long if and else ladders and really long if statements or else statements and really long blocks. And then maybe somewhere inside, you're doing a select something from the database that you could have just done at the beginning for multiple IDs instead of just looping through the IDs and doing that one by one, something that it's easy to miss. And then you get into the things like, use is empty array instead of count array equals zero zero or use a triple equal instead of string compare for string comparison because it's faster. And then use single quotes instead of double quotes when you're not concatenating, which is my absolute favorite. And then people say, oh use regex instead of some crazy string mangling that you do manually, but then don't use regex because it's less efficient than the native PHP functions. So you're all like, what? And coming back to the list of issues, none of those things actually address any of this. None of those tips will help us actually sort solve the easy issues. And on one hand, you don't want to ignore these things because they are just good coding habits. You might as well follow the good habits. And even if they might seem insignificant on their own, sometimes a lot of tiny optimizations might actually add up to something actually making a big difference. So don't necessarily ignore them. And this kind of stuff might matter if you're not actually addressing an actual problem with a memory leak. Maybe you're just trying to squeeze out like the last bit of performance juice out of your app. Then yeah, maybe those tiny optimizations will actually make a difference.  And just to show you this, so these are some stats taken from, I've got a link here, I've shared the slides already so you can check out the whole website. So this is from Thimo Matig's website. So he runs PHP benchmarks live on his server. The server is running PHP 5.3, but it doesn't really matter because it's kind of the same thing in seven even. And he's just compared to the typical things that you find on the internet and just to see if this is actually true. So this is the single and double quote myth.  I mean, that's a drop in the ocean. That's not really causing your memory issues. And there are some other ones.  You know, should the variable go before the constant and on an equals comparison or the other way around? No difference whatsoever, three milliseconds. You know, if you're doing hastag zero is n or string position to just check the first character, no difference. String replace compared to preg replace only three milliseconds difference. I mean, that's not a huge difference. And all of those tips, what they all have in common is that they're all micro-optimization. So I would say 99% of the time, ignore them every time. It is worth looking into those things when you have evidence that they are actually causing problems or they are a bottleneck. And you should try to micro-optimize maybe bits of your code, not the entire app. I mean, don't go off and start changing the double quotes to single quotes everywhere. And that's probably not the way to go. It's probably not worth spending time on or arguing about, I mean, I've had so many pointless, it's like Vim versus Emacs, which quotes should you use? And you should always benchmark and measure to prove that you're actually improving situations. Don't just do this because you've read about it on the internet. Somebody on Stack Overflow five years ago said that that's what you should do. No, always measure, always prove that you're actually doing something right. And most importantly, don't miss the real bottleneck. Like don't focus on these things because there's probably some more important issues to tackle. So focus on the whole paths in your code or whole areas. Well, that's all good and well and good. Focus on the whole paths and areas if you know how.  And I got stuck on that as well. If you already know how, that's all well and good. But really, how, how do I know? How do I know, want to improve? How do I know how my app is doing? How do I gain that visibility into my code? How do I know what my app can handle in production? How do I know it's not leaking memory? How do I prove that? No, will I run out of memory? Or maybe I am over provisioning and maybe my app doesn't need the massive server that is running on. How do I prove my guesses? How do I prove my theories? And the general answer is of course measure. But then, how do you measure? And what do you measure? And how often do you measure? So I was there myself, I had all these questions. So I thought it might be useful to do a practical example of maybe how you could go about answering those questions. And how do you actually go about doing it? So let's start with the tools. And this is potentially the first very confusing, very overwhelming things when you're starting out because there are so many of them. And people tell you, use this, use that, use this. And you're like, well, but what is everything for? Like, how do I, you know, why, when should I use this, when should I use that? And it is important to know what each tool is useful for. Like, what's the purpose of a tool? And I've kind of tried to group them here by roughly what the purpose is. So you've got your monitoring tools at the top.  And you might be lucky enough to actually already have something like that set up for your system so you may already have some performance data available. You know, if you've got something monitoring your memory usage or CPU usage, for example, you've already got some data. And that will give you the bigger picture, the idea of how your app is doing in general, how it's doing over time, has it gotten slower, hasn't gotten faster. And you might be able to tell from those graphs and from those tools, if there is anything that you need to worry about, you know, if you see spikes, if you see something worrying, then you probably know that you should look at your app. If you don't have any production data available, you could use the load testing or the benchmarking tools. And those are basically the tools that will generate the load for you. And there is a million of them. I've only listed here a bunch of them. My favorite one is Go work for simple things. That's a Go app. And it's just a really simple, simple to use app. There are some more complicated ones that take a little bit more time to learn and use. So things like JMeter or Gatling and Taurus or Apache Bench, they allow you to do a lot more. They allow you to customize your load. They allow you to specify different prams, the vary the load, that sort of thing. But they are a little bit more difficult to set up. And sometimes, you know, just a really big loop in your code, like for 10,000 iterations, do this. That's also load generation, you know? So you can actually just do it yourself. And the goal here, like the goal of those load testing and benchmarking tools is really just to avoid sitting there and refreshing your app multiple times, especially if you want loads of data. Like you're not gonna sit there and press the refresh button 10,000 times. So that's what those tools are for. But monitoring and benchmarking will only give you a higher level view and sort of higher level data about your app. They won't really tell you what's going on inside your app. And so to dig deeper, you need more detailed information. You need things like low level stats and stack traces and your memory usage and execution time for every single function in your code, ideally. So you need something called a profiler.  So you usually need some visualization on top of it to actually help you make sense of all the data that you have. So how does that look for PHP? Well, for starters, none of this is built into the language, which is great. I mean, compared to Go, Go has most of these tools just shipped with the language. So actually when you install Go, you install all those tools. With PHP, when you install PHP, you install PHP. You don't have any profilers available. You could roll your own. I mean, to be honest, I'm not against just doing microtime at the beginning, microtime at the end, and then just to subtract them. That's how long my function take. I mean, for quick and easy and quick and dirty sort of measurements, I think that's completely fine.  So to do that, you kind of need a more professional tool. And most of those tools are available as PHP extensions. Luckily, you don't need much extension food to get going. I mean, I'm not an extensions expert, and I managed to install a lot of them. It's quite easy. So just to recap, this is how you can install PHP extensions. I'll probably go through this pretty quickly, because hopefully you know this. Your mileage might vary, because obviously, depending on what platform you're in, how old is your operating system, that kind of thing, some packages may or may not be available. The actually most convenient way these days for me, because I run a Mac, is just to use Homebrew if I can for all the extensions. So if Homebrew or whatever package manager you have, like yum, apt-get, whatever your distribution is, you just do that, install, name, and boom, done. Your extension is on your system. You can use Peckle, which is part of Pear. So once you install Peckle on your system, you can do Peckle, install, name of the package. That should work. The S-word. Or you could compile from source, and that's actually not as scary as it sounds. So what you have to do is just get your source code down, so you usually get cloned or something. Go into that directory.  This is kind of like Installing C apps. Whoever did C development, this will sound familiar, because PHP is written in C. Any options for the extensions, usually the readme for the extension will have those instructions there. So always check out the readme. This is just like a generalized list. Then you do make, make install, and then you need to not forget to put your any file in your PHPs, like conf.d, any directory, because that's how you actually load the extension into PHP. So you tell PHP, use that extension, and you can specify your any values there. If you do peckle or brew, those any files are usually created for you automatically, so you can just edit them. On the Mac, I believe it's user local, ETC, PHP version, and then conf.d, and that's where your files live. If you're using brew, homebrew, which to be honest, I recommend it because it's just the least painful way. So let's get ourselves a profiler. This is a list of the ones that I found. There is probably a lot more in GitHub. The first one, APD, that used to be an extension used for profiling and debugging, but it is actually no longer maintained. I think the last main paint update was 2004, 2007, so I kind of crossed that out because I think we should just forget about it. The two most popular ones, and I probably all heard about them, is ex-debug and ex-hprof, and then other people wonder like, what's the difference between them and which one should I pick? So both are installed as PHP extensions. They are both available via homebrew, for example, which is slightly easier. I'm pretty sure Apped Get has packages as well. And the deal with that is that in the old days of PHP 5, old, some of us are still on PHP 5, but in the old days ex-debug didn't have memory profiling built into it, so you could do your step debugging and you could do some profiling, but you didn't have the memory information, whereas ex-hprof, which was developed by Facebook, and then open sourced, that gave you all the memory information, so you kind of had to use both. But since PHP 7, Facebook is no longer maintaining ex-hprof because they've moved from Zend to HHVM, so they've abandoned that, and luckily some kind souls created PHP 7 forex of the ex-hprof extension. So the two probably most popular ones are Tideways, and again, I've put links here, I've shared the slides so you can click through it and find it on GitHub. So Tideways ex-hprof extension, which kind of is now just becoming their own product and their own thing, and they've slightly modified the original ex-hprof, or there's this Chinese person on GitHub that I will probably butch the name, so I'm not gonna attempt to read that, but that Chinese person has created a fork for PHP 7, which is actually very, very close to the original ex-hprof. And in terms of when you should use these, they are absolutely not mutually exclusive, so you can have both installed on your system and you can use both at the same time. The one thing to remember is ex-debug should only ever be run in development. I mean, it will make your app a lot slower if you use it, so don't ever run it on production. Ex-hprof can be used on production if you had to. It's actually, it's got such a small footprint that it won't really affect the performance of your app, so that's something to keep in mind. If you have to use something on production, it's probably gonna be ex-hprof. And then there are other things, like the memory profiler and the mem info, there are two other extensions that also allow you to profile your memory. We're gonna have a look at PHP memory info in a bit. And there is probably a lot more, but I just didn't have time to go through all of them. So, guessing really isn't enough. Like I mean, you might have some ideas to start with for what might be causing your issues, but you really need to work out and prove what's going on in your app. So you need to do some diagnostics before you do the diagnosis. Now, so I tried to find a real-life example to do that demo on, and then anything I worked on at work would just be too big and it would just take way too much time to explain what it does. And I would probably borrow you to death. And I also didn't want to give you an example with like foo and bar and class A and class B, because that's not really how real life is. I mean, we can all optimize a five-long PHP app, but that's just not what real life is like. So then a friend of mine, Matt, that you probably know, you probably know Branti, he tweeted about his site project. And I just randomly had a look and I was like, oh, this is a really lovely PHP 7 app that just fits that need perfectly to command line up. So I used Branti's app for my demo. Cigar, which is the name of the app, it's a smoke testing tool. So what you do is just you specify the URLs and the expected HTTP code and any expected content if you have it. And Cigar will just run through the list that you specify in the file and compare what you expected to get with what you actually got. And if everything's fine, you'll go, yep, I checked those URLs, I got the HTTP codes that you expected, I got the content that you expected, everything's fine. That's all it does. So you already know it will make some external calls to the internet. And you don't really need to know the full details. I'm kind of doing this on purpose right now because in the real life, very often when you're asked to optimize something or look at something, you might know very little about the app. You might not be the one, the person that originally coded that in. So you might even not know what the code does. You know, all you have is just some vague idea for what the app does. So let's imagine the first scenario. The app is running slowly. Somebody comes along to us one day and says, hey, that's a cigar tool. That used to take, you know, not 0.5 seconds to run. Now it's taking something like three seconds. What's going on? So, well, we can set up XHPROF to start with and see what that gives us. So the way you set up XHPROF is, this is on the readme, so you can just copy and paste from the readme. You basically just add a bit of code at the beginning of your file and then at the end. So the first bit is just enabling XHPROF and then the second bit is just disabling it and then saving the data to a file. And you can just copy and paste like I did here. So copy and paste in any file that you need. It doesn't have to be right at the beginning or right at the end. Like you can just profile bits of your app. You can check those two bits of code in a separate file and then include them or require them for every file to avoid copying and pasting this all over the place. Or you could use the auto-prepand and auto-append any directives to then get PHP to automatically prepend and append those two bits to your code so you just don't have to worry about it.  The original XHPROF gives you a way to view the results in a browser. The tidways extension, and that's the reason why I actually haven't used that extension for this demo, I think they've gotten rid of the original one because I couldn't find it anywhere. There is a directory called xhprof underscore HTML which is actually the HTML viewer. And that's not in the tidways extensions or at least I couldn't find it. So I think they might have gotten rid of it. In the original XHPROF, this is the original kind of UI that you get when you run it.  I mean, this is all on the read me as well so you don't have to remember it. And that's the first page. So what you see here is, well, we've got the main function here and then we've got some of our code, some of our cigar code. We've got the parse function, we've got get URL objects and then we've got a closure here. So, and those are the top three ones here and they seem to be taking over two million microseconds. I think that's the unit that they use here. So the first most important thing, and that's again what a lot of people tend to forget is to establish a baseline. So before you actually go and change a single line, you need to know how your app is doing now so then you can compare after your changes, you can compare the results after your changes and see if you've improved things or maybe you've made things worse. So always make sure that you grab that baseline first before you go off and change things. So our baseline is the 3.0, 64 seconds that we saw earlier on. And then XhProf also, whoa, this is really bleak, but it doesn't really matter here. So XhProf also gives you a call graph. You can click on the call graph link and it will help, it will try to be helpful and it will try to show you a hot path here. So this one you probably can't see this, but this one is the parse function. The big red thing is the parse function. So it kind of agrees with what we saw on the list. So XhProf is kind of saying that, whoa, this parse function is taking the most time. But that's kind of as close as we can get to the code with XhProf. We don't really know what's inside that red box. We don't really know what the code is. So, but at least we know now what area to focus on. I mean, we know this that get URL objects function is something that is causing problems. So at least it allowed us to like zoom into the bit of code that we might be interested in. But then how do we find out what's going on inside that function? We could obviously look at the source code at this point, which is something that we might do. But let's use XDbug. So the way you set up XDbug, this is actually something that you get out of the box if you use homebrew. It's just three directives. You basically just enable it, give you the output directory for where to save your output files, and then just give the output name for the files. So you save the files as cashgrind.out with some random number at the end so you don't get clashes. And then what that will do is every time you run your app, whether it's a browser app or a command line app, XDbug will work and profile your app behind the scenes and save the results to a file. But then again, the file when you open it is just a random string of nonsense, really. It's not nonsense, but it doesn't make any sense to you. So there are lots of UIs to view XDbug data. I'm gonna use Qcashgrind or Kcashgrind, I think it's on Linux, which that tool looks like it's from 1995.  There are other ones. There are paid versions on Apple Store. You can use something called Webgrind. So there are a few options, but Qcashgrind is actually not too hard to install these days. You can install it via brew with the caveat that you can't see because it's not visible enough. But basically on the latest Mac, if you install it via brew, because of the changes to security that they've done that you can't put binaries into user bin anymore and they are in local, Qcashgrind can't find some of the binaries it needs. So this is a workaround thing, and I've shared the slides already, so you can, if you run into this, this is a tiny workaround, you create a shell wrapper around it to get it going. So it does work on the latest Mac, even though it really looks like an app from kind of like 1995 up. So first of all, you have a dropdown here called, sorry, there is a dropdown with time or memory. So you can select, do you wanna view time information or memory information? So we wanna view time because we're now looking at time. And then we've got the same parser functions at the top here. So we kind of see the same results as XHPROF. And on the right, you've got something called the color map, and that gives you this weird looking pyramid diagram. And it might look very confusing at first, but basically if you're looking at performance, what you're looking for is big squares with nothing in them, because that means that proportionately that square, that green square took the most time in the app, but it didn't call any functions. There was nothing inside it, no squares inside it, which means it was the last function that the profiler in the profiling trace that was found most of the time. And when you hover over it, that hover is the parse class here. So again, the way you read it is those little squares here, you might think that, oh, that's really busy, that's something going on in here. That's actually nothing to worry about. That's just lots of functions calling other functions and taking a relatively small time overall. So what else can we get from Qcache grind? Well, at the bottom there is a tab called call graph. So you can get the call graph and we see the same things as XHPROF. And then we can see here that this one is the closure. So this is taking a fairly long time. And closures are one of those things that are really, really hard to debug when it comes to performance because the tool won't give you a name of a function right away to look into. They will just say like, oh, in this file, there's a closure and sometimes you might need to work out which one is it? So that's a little bit tricky to work out. And then if you compare the two, I just did it for just out of curiosity. Comparing the two call graphs, they look the same. So they are from two separate runs. So the overall time parse in XHPROF is shown as 81% of the time. And then here it's 79% of the time but that's because it's two separate runs. So your data will vary between the runs slightly but we do kind of get the same general idea that that parse function and that one seems to be taking quite a while. So back to Qcache grind. We select the second function from the top. So the top one is main which is always gonna be at the top, obviously. And then there is the array map function. And here you can see, so the top section here is the colors of that function and then the bottom one is the callees of that function. And in the callees, you can see that closure. Well, you can't see it because it's probably not visible but that has the closure in the list. So then you can do even more cool stuff in Qcache grind. You can view the source code here. So when you click on the view source code, well, some weird stuff like high equals four, that kind of thing. Or maybe somebody might have put some code in there to calculate pi as well as fetching the URLs in the get URLs for objects function. So when you then look at the code, that's actually, I've just pasted that in, it wasn't mad, it was me. So I just made it slow on purpose to make it show in the graphs but that's kind of how you arrive at what bit of code exactly is taking the most time. And so then when we remove the pi code, we've improved things, it's back to 0.3 seconds. Ooh, surprise, surprise. So we've got our proof here. We've actually, you know, we've got some numbers. So it's not just me saying, oh, I think that was it. You know, I've actually got proof that I've got it down from three seconds to 0.3 which is kind of what you want. And then just for completeness, we run XH prof again. This is the top of the list of the functions. It doesn't show up there anymore. There's no parse here, there's no parse here. And then somewhere at the bottom, there is the get URL page and it's now, so now it's something like 737 microseconds versus the over 2 million milliseconds. So XH prof is saying the same thing. We've made it better. And again, this doesn't really show up too well but this is the call graphs and now, so this is the old one where the parse was here and then parse is somewhere here which you completely can't see, I apologize. But now XH prof is showing us a different hot path that it thinks might be now the busiest path and you also can't see it, but this is all Guzzle classes. So Guzzle is an HTTP library that you use for making requests and then we know that this app is likely to make external requests. So this isn't necessarily worrying because, well, it's what we expect from this app to use Guzzle and to mostly use Guzzle to do its job. So this is not alarming anymore. One thing I would say is don't discount library code from when you're optimizing performance because the fact that it's a library, it's still code, it can still have bugs, it can still have memory leaks. I mean, at work, we've had a memory leak in one of the metrics libraries that we've used. So when you're looking at performance, just because you see some familiar names like, oh, it's Guzzle or it's Symphony or it's Zend or whatever, you know, most of the time you can trust that they've done a good job and they don't have any issues and it's just because the app, you know, mostly makes external calls, but it could be, you know, if you spent hours looking at something and all your clues point at a library code by all means look at it because it might actually have some issues. And they make a pull request, obviously. So then back to Qcashgrind, we've got parse. We don't have parse at the top. There is a handy search as well, so you don't have to look through it. Now we're near at the top. This now looks different and now this is also Guzzle so we can see that Guzzle is taking proportionally the most time. So this is kind of what we expect now. That was a good spare step. You know, that was like, yeah, we've done something good. By the way, you can also view XDBug profiling things in PHPStorm for those of you who use it. In tools, you've got something called Analyze XDBug Profiler and that gives you something like that. It gives you nowhere near as much information as Qcashgrind, so it's not really a replacement, but if you just wanted to view something quickly, you can do that. It gives you something called like a call tree so you can like in a typical PHPStorm way, you can do the drop down drill into the drop downs. One caveat with that is with PHP 7.2, the stable PHPStorm version doesn't actually work with this. It can't open the XDBug 2.6 files. So I had to install the EAP version and the EAP version seems to be fixed for that. So I think it's in the 2018 release that they will actually put those bug fixes in. So just to keep it in mind that you might have to go for the EAP version if you wanna use this for XDBug. So what more can we get here from the XDBug output and what more can we see in Qcashgrind? Well, one of the cool things it shows you is this column shows you the number of times a function was called, which is really handy sometimes. So here, for example, we've got 123 calls to string to lower, and you might be wondering like, well, why is that? And then again, you can look at the colors list which is really handy because that shows you all the classes and all the functions that have called PHPStringToLower, which is quite handy. And here we can see that, so all of these are again, guzzle functions, and all of these functions here are to do with headers. So it's something like set header, get header, add header, that kind of thing. So we can guess that guzzle is lowering all the strings using that function when it's setting the headers. And again, because it's doing a lot of external requests, it's no wonder that it's doing over 100 calls to that function. So the reason why I'm showing you this is that you can really gain a lot of understanding of what your code is doing when you do something like that. You can click around here, all of this is clickable. You can just click on these things and get an understanding for what's exactly calling this. Is this something that should be worried about or is this normal? And I don't know what else can we see. So we can see that we have nine calls to the fopen function. And well, we know that our, the Cigar app is only opening a file once. It's got one config file that it will read the list of URLs from. So we'd expect more like one call to fopen. And again, looking at the colors list here, we can see that this is our get file contents function, which is actually the one that, the config file that we are reading. There is also some guzzle things. And again, you might be wondering what is guzzle open doing with fopen? Like is it opening files? No, maybe it's some temporary files that it writes down. And again, you can look at the source code and you can see here that is the PHP temp. Some writes to PHP temp. So then now you know that guzzle is actually writing some temporary files as part of its work. And again, that kind of visibility you can gain by just clicking around. So now we can flip the dropdown here to memory and come back to our get file contents function. You can search for it or you can just find it in the list. So we click on that and you can see that the, we do like an fopen, fread and fclose and that seems to be taking quite a bit of memory. And I wonder, because since we, and this is kind of the part that mostly just comes with your experience or how quickly the light bulb is gonna go off in your head. But when you think about it, we're only reading from the config file. We're not writing to it. And there's a different function in PHP for doing just reading from file called file get contents. So again, you might be wondering, well, is it gonna be faster if I use that function instead? Or like, is there gonna be any difference at all? And so we swap that function and then sure enough, just file get contents here. Now gives you instead of over 8,000 here in the memory, forget what the units are, I think it's bytes. Now it's like 496. And then overall, if you look at the colors list, so the parse function, which then inside calls the get file contents, that was 512 before and now it's 496 now. So again, you know now that using that function is faster in your case. So you should probably go with it. But again, you've got the hard proof. You've got the numbers and this is actually better. And this is so easy to play around with as well. Like you can, all you have to do is edit your code. Your ex debug is running in the background. You just run your app again, you get a new file, you open it in cash grind and you've got different results. So this is a really quick feedback loop. It's not, we're not talking like minutes to compile or anything. So it's really easy to play around with this. If you wanna play around with using different functions, see if it makes a difference, maybe it does, maybe it doesn't. And by the way, for this case, XH Proph wouldn't show us any of this information. So in the UI, you can click through things. So when I click on the get file contents thing, function from the first list, this is as far as it gets me. Clicking on that link takes you nowhere further. So this is all you get. And this is the call graph and it just shows you that parse function that then calls get file contents. But you don't know anything more than that. Like F open doesn't show here. So you wouldn't get that information from XH Proph in this case. And this is why you should really use all the tools. I mean, don't just stick to one because sometimes it might help you, sometimes both might show you the same results, but sometimes one of them might be much better than the other or show you more information. So by all means, go ahead and use as many as you want or try out new ones. So what if you want to do some general explorations? I mean, those were things that we could kind of spot as maybe potential problems, but what if you wanna just know what's inside your memory in your app? Maybe there is something that could not be there. So, and how do you check that your program is not leaking memory for sure? You can look at the memory numbers in XDbug or XH Proph and kind of guess on that, roughly how much memory you're taking and does it go up between the runs? Does it not go up? You could watch your monitoring graphs, your production monitoring graphs. Obviously, those are good things. And if you look at the GC stats, for example, if you see something like this, so these are all the GC phases, that's okay because the overall, this is flat. So as long as this stays flat, that's fine. This is just GC doing its stuff. But it would be nice to know what's in our memory at the end of the run of your program. Like what exactly, what objects are there when you finish running your program? So for that, we can use the PHP Mem Info extension. Again, once you install it, you just need to add one line. So at the end, this basically just tells to save the output to a file. It saves output in JSON files, so you can actually open them and make sense of them, which is nice. So this is all you have to do. You just do Mem Info dump, and it will shove some information into the file that you can then analyze and explore. It also comes with an analyzer that is just a PHP app. So it comes bundled up with everything you need. So let's add that to the end of the parser file and the, sorry, not the parser file. So this is the entry, whoops, the entry file to Cigar. So every PHP app is gonna start with the procedural file. So this is the main binary file for Cigar. So we just added at the end of the main file. So we know that we're gonna get the data at the end of the whole app. And then you use the analyzer. So it's just a binary that you run. And you've got a summary call, for example, which is a good one to start with. So you just do summary and then the name of the file, and it gives you something like this. And it gives you the exact count of all the objects that are in the memory when we dump the output to the file. So we can see how many instances of everything are there. I mean, there is some outputter and parser, which is the Cigar code. And there are strings, array, integers, there is URLs, there is results, all sorts of things. We've got 44 strings, for example, this is how much memory they are taking. It's pretty useful. And the cool thing about it is that if there was a memory leak, you'd probably see an object that you wouldn't expect to see here. Like if there was an object that you would think, like why is it here? And on top of that, if there was like 100 and something instances of it, that might be a warning sign. So this is quite a good output. Like we see nothing warning, alarming here, but if you did see like a random object that you would think it should be long gone and there's 124 of those things and maybe there shouldn't be, that's a really good tool for that to spot any of this. And by the way, for this demonstration, I tried to create a memory leak to show you like an actual memory leak here, but it's really, really hard to trick PHP 7 into memory leaks these days. Like all my tricks I've known from PHP 5 don't work for PHP 7. So if you leave open file handles, if you leave circular references to objects, none of this works in PHP 7 anymore. It's gotten a lot more clever. So let's just for the sake of the demonstration and see what we have here. Well, we've got our favorite parser object again. But then if you think about it, when we look at the source code, we create the new parser objects and then we parse the file to get the config, so get the URLs that we're gonna call and then we do the calling. Like we do this asynchronously. So we only read the file once so we only need the parser object once and never again, because we only read the file information once. So why the hell is it still in memory at the end of it? It could be that because overall your program is not taking a huge amount of memory, the GC just doesn't get to it. Like maybe if there was more memory the parser object would get cleaned as part of it, but maybe not. So why is GC is not cleaning it? Like why is that object still there at the end of the file when we only use it here and we don't really need it anymore? So it looks like we are creating a variable here and we're using it here. And when you look at the query command in the analyzer, you can filter it by class as well so we can zoom into the parser function specifically. Then it gives you all the information about that particular object in memory. So it gives you the ID of the object, tells you that it's an object of this class. There's two references to it and it's a root so it's not a child object. And it's in the global execution frame which is what we would expect because we're in the main procedural file so it's a global scope. And then can we dig deeper? Like well we can, we can use this ID in the next command which is the ref path command which shows you all the references to that object. So we have two references here. One of them is the self reference here which is the self reference from the object to itself and every PHP object will have it. And then the other one is from the global scope to the parser object. So that kind of gives you an idea for, if you wanna find out, if you've got lots of objects in your memory and you wanna know what is the reference that is preventing this object from being GC'd, then that's a great tool to use because that will show you exactly what is still referencing that object. Like in this case this is not alarming, this is just self and global, this is what we expect. But if there was something suspicious, if like something else was referencing this object or that we wouldn't expect it should show up here. So that gives you a good idea. So out of curiosity we can look at the global's ID as well. So in the previous one you can have the ID here for the global scope and if you do that you can see all the familiar PHP things. So this is a getPost, cookie, files, request server. All of that stuff is here in memory in the global scope. So can we make that parser object go away? I mean we know we don't need it. So is there a way to do that? Well PHP gives you the option of creating that object on the fly and then calling that function on the newly created object but without really keeping a variable attached to it. So does it change things if we do that instead? I mean we know we don't need that parser variable anymore. So then we run the analyzer again after we run the summary command again and then it's gone, it's no longer in memory. So again we've got the hard proof that we've done it and it's no longer here in memory. And this is something, this is a good trick to keep in mind that sort of dynamic reference. If you know you're creating an object just for a single use and you might not need it anymore especially if it's in the global scope and you wanna make sure that it doesn't necessarily hog the memory, that's a good trick to keep in mind. And again, you can run your analyzer to then find out if it's actually working or not. So just to make it clear, I have to make it clear, none of these things were in Brunti's original code. He didn't make any of those mistakes. He's done his performance homework. I have made a lot of edits to this code to make it bad. So thank you Matt for letting me use this. So I hope it was useful to see the demo like this and I hope it seems a bit less scary now. There are many, many more tools out there. All of them have read me so you can probably work out how to run them. It might seem a bit, I mean this was a small demo and I already knew where I was going with things. Normal performance optimization might seem very tedious at times. It might seem a bit daunting but it is so rewarding at the end of the day. It's really worth it. I mean, the feeding that you get when you get the final result and you go, yes, I've got it down from like three seconds to not point five seconds. It's really worth it even though it might seem a bit tedious. Some key takeaways just to summarize. Prioritize what to focus on. Look at the gains versus effort. It would take to optimize something and focus on the most important things first. I mean, the reality for most of us is that we're given a specific time to optimize a project and you're just never gonna do everything that you want to do. So just focus on the most important things. And ignore micro-optimizations unless you really, really have a good reason to worry about them. Design changes sometimes redesigning your whole app like actually changing how it works is way more important than single code changes or your flipping of your single quotes or double quotes. Usually try to focus on the hot paths. I mean, you can use the XH Pro as a guidance for what's a hot path but not always. Sometimes the hot path is there because that's the nature of the app so definitely don't ignore the rest of the tree. Don't sort of take it for a silver bullet always. Customize your optimization for your needs. I mean, there is usually more than one way to optimize. There's usually more than one correct answer to make something better and don't be afraid to break the rules. Don't be afraid to break the rules if it works for your use case. So it's kind of the same thing as denormalizing databases. I mean, in theory, you shouldn't do that because you're denormalizing things but actually if it works for your particular use case, then you should do it and it's the same with performance. I mean, maybe you're not doing something textbook correct but if it works for your case, if it makes it up faster, don't be afraid to do that. Use the data to prove your guesses, measure everything. Keep in mind to do this with minimal impact on performance, especially in production. So try and avoid profiling in production if you can. You can just do all of that stuff in your web development but always measure everything. Always have the benchmarks to prove your guesses. And remember that performance optimization is an iterative process. I mean, it's not enough to do it once. You usually have to come back to it over time. You need to know your trends over time. You need to observe how they change over time. So have monitoring in place. Maybe have some alerting in place based on the trends. You could run your automated load tests to prevent degrading performance. So you could run it after every commit even to make sure that it doesn't make things worse. And for the VIP experience, this is something that Etsy does and they have a really good blog post about it. They actually have a graph which shows the memory usage and they've correlated that with deployment. So actually they have vertical lines for every time they deploy something. And then you can easily see that after this deployment, the graph suddenly spikes. So you know exactly what deployment, which deployment made things worse. Which again, just helps you narrow things down a lot faster. That is all from me. Thank you very much. Thank you.


welcome to drinks made easy today we're making the smoking skulls no no no don't drink that yet why tell you in a second to build your smoking skull you're gonna start with two ounces of bourbon next you're gonna add three quarters of an ounce of fresh lime juice and half an ounce of grenadine now we always tend to recommend using natural grenadine but because it's a Halloween drink that we're trying to get really bright and red we are using the artificial grenadine now we're not gonna shake this with any ice today because when we do use ice you're gonna chill down the temperature of your contents and because we're gonna be using dry ice we want this to be a little bit warmer so we get more of a response and more smoke and bubbles so give it a quick dry shake into your skull glass with a few ice cubes pour in contents and top it off with a little bit of Mountain Dew and now the magic and there you have the smoking skull cheers and drinks man easy don't don't drink it yeah what you have to wait until the dry ice is either completely dissolved or take it out of your drink why well because it's negative a hundred nine degrees and it's also solid CO2 so if you can consume it it can also make your stomach explode like happen to a gal in London a couple years ago oh yeah so never ever ever consume a drink that still has dry ice in it and please remember to always drink responsibly because everybody likes to make friends but no one likes to make them in a prison shower we're gonna need to do another one of that that was perfect no wasn't