[00:02] coding agent to assist with performance optimizations? Yes, you can. And this video, I will show you how. Performance optimizations is a highly specialized topic, and I understand not every developer should know all the ins [00:16] and outs of optimizing performance. A profiler provides all the necessary data, but you as a developer still need to analyze, understand, and make the optimizations yourself. It can be quite difficult because every bottleneck is [00:30] different. I combined Cloud Code with two PHP profilers to optimize the JSON previous video. The AI agent gives me insights into the bottlenecks and how to fix them. AI-assisted development is everywhere [00:46] now, and we have been experimenting with it in the Tighten team as well. In this video, I'm going to show you the current state of AI agent and Tighten integration, and also how you can integrate it with PHP SPX. Hi, I am [01:00] Benjamin, and I am helping PHP developers like you with performance optimizations for over 10 years now. Let's dive into the JSON logic example. It's a library that allows you to execute JSON logic rules in PHP. A JSON [01:16] logic rule is condition, a mathematical expression represented in JSON, and then you can put it into this library, apply sort of the calculation for this rule, and you can also pass in context information to [01:32] have a dynamic calculation. I stumbled over this library while reviewing the performance of a customer's e-commerce shop, and I've optimized it in a video previously with many different patches, and the performance was increased [01:47] considerably. So, today I want to see if an AI agent can also do this performance optimizations, if it can find the performance problems by looking at performance data directly from Tideways. [02:03] For this, I'm using Cloud Code. I've set it up in my Visual I've set it up in my Visual Studio. I've been using a sandbox for this. [02:18] sandbox Cloud. So, I'm putting it into a Docker container so it doesn't have access to my whole host system. In Tideways, I'm enabling the AI agent support in the beta feature section. [02:33] And then I'm going to my editor and see how we can make this work. So, I've set up a very small project that has a complex.php [02:45] with a very complex JSON logic rule from this customer that I helped. And they have a Shopware shop and are using a plugin that has dynamic price calculation using JSON logic rules. And this is just one [03:00] of the very complex rules that they have. Very complex data. So, this is a dummy I've set up that shows the performance problems. I'm iterating over the data. I'm iterating 10,000 times. [03:15] have some slightly different calculations. And then I'm applying these rules to get the again. So, let's look into Cloud Code and see [03:29] what we can do here. I can tell it to look at look at Tideways run PHP complex PHP result. [03:47] find performance bottlenecks sorted by impact. So, what it's doing now, it's running the tight race run command with this [04:02] the tight race run command with this this complex script that's using the this complex script that's using the JSON logic library API with an example from the customer I helped. They are using Shopware 6 and a [04:15] helped. They are using Shopware 6 and a pricing plugin that uses dynamic JSON logic rules to do very complex pricing calculations. And as you can see, it's quite quite the big JSON document and then also quite the big [04:27] context information, different prices for different things. I iterate 10,000 times and then apply the rules. And now let's see how this will look like if we run Cloud Code and optimize this for us. [04:45] and optimize this for us. So, I've set up a project using the JSON as a dependency through composer, installed it. installed it. And also have a complex PHP file, which [04:59] is an example from the customer with one of their very complex if conditions for of their very complex if conditions for pricing and based on various rules in their Shopware in shop. And also some context data. [05:15] And I iterate over that context data 10,000 times change some of it to have different results with every iteration. And then apply the rules the data and [05:27] rules together together result. And now I'm going to run this through the profiler to see to find out how to optimize it. So, let's use Cloud Code now to find potential performance problems and make [05:41] suggestions on optimizing them. First, we need to tell that it doesn't need to optimize complex PHP. Do not look to optimize complex PHP. We want to find problems in JSON logic library itself. [05:59] And then call call Tideways run PHP complex PHP and look at the output for performance insights. [06:20] now, we can see the output that Tideways returns. Um control O, it shows us the call graph information. All the different calls, how often it was called, and the total time. And based on this, Claude can now run [06:35] based on this, Claude can now run optimizations and find the problems. library and then make suggestions for improvements. [06:47] improvements. So, what we can see now the um improvements it suggests is operators array rebuilt on every apply call is the biggest issue. Line 61 to 169. [07:02] Uh the entire 30 operators array is recreated on every invocation of apply. So, and if you remember the video I made before, this was the first optimization that we looked at. There's actually a pull request and a [07:17] patch for um optimizing apply by moving operators into a static array where possible. So, let's see and ask Claude if this already fixes the issue um and optimize from there. [07:38] Look at the patch and does it fix issue number one? Uh Claude will think about this. It first tries using the GitHub CLI. It's not uh [07:53] uh authenticated here, so it's now uh downloading this using curl. downloading this using curl. It's a little uh less efficient. [08:06] only partially. What it does moves the operator array initialized once. The catch var missing missing are closures that capture data via use, so they cannot be made static. They still get recreated in line on every call. Those [08:21] three are extracted and handled separately, while the 20 other operators are cached and statically. So, it fixes the lion's share of issue one, but the var missing missing some closures remain per call allocations. [08:37] um apply the uh would you make a different approach to fixing the issue? Um in the time we can open this [08:52] Um in the time we can open this code block and look at it ourselves. objected to apply is creating those closures over and over again. [09:07] closures over and over again. Yes, so it would do a different I fix I'd apply move var into the else chain eliminates all remaining call closure eliminates all remaining call closure plan. [09:28] suggestions don't do three and four. We look at them later. Uh so, uh, is now working on this Uh so, uh, is now working on this change. [09:45] This is similar to the patch, so it's not directly applying the patch, but it's doing some changes based on that. And we have this extracted out now. [10:08] Var miss me as is branches wire up the static operators update. static operators update. It's doing it here now. [10:25] and then it's running the complex profiling data again. profiling data again. And it says it's, uh, 40% improvements. [10:39] numbers, so call user func array dropped from 217,000 calls to 84,000 calls. And is object dropped from this to that and, uh, some more. So, the right [10:51] meaning hotspots are now is logic and get operator array keys. wanted to tackle next. And then I'm saying explain [11:04] saying explain issue three in more detail. [11:17] containing all keys of logic just so that we can read index zero and throw the rest away. Since the logic node always has exactly one key, that's what is logic enforces. This always allocates a single element array as an an value [11:30] that is immediately discarded. The PHP function array_key_first, available since PHP 7.3, does exactly what we want, return the first key directly, no intermediate array. The reason this matters is call volume. [11:43] Get operator is called from three places, apply, get values, is logic. Current profile has 1 million calls to get operator. perform. So, we see now array uh the get operator [11:58] So, we see now array uh the get operator logic uses array_key_first. Then, let's see what Claude sees as an improvement. It's a modest gain. array_keys is gone, replaced by array_key_first. The overhead of calling [12:11] get operator as method still dominates over the actual work inside. over the actual work inside. So, 1 million. That's the next logical thing to look at. It calls get operator on [12:26] every invocation. It's called far more than necessary gives in the play. than necessary gives in the play. So, [12:43] As you can see, it's thinking again instead of implying what it thought about before. It inlines the array_key_first now because get operator is just a simple call now, and then we can see what [12:56] improves in the performance if it does that. optimizations that Claude did for us, but it didn't fix like the primary ones [13:10] that we did when we did the manual operation. So, there's still something operation. So, there's still something left here. So, [13:22] in tight base itself to maybe see some in inspiration of what was done before. So, what we can see here is logic still takes up the most amount of time. Um [13:34] what we can see here we have is array count and that is something that we count and that is something that we fixed um in the in the other video. We used compiler [13:47] optimized function importing to get rid of these calls and having the engine do them. So, let's go back and suggest this to Claude. So, this is the step where Tighten ways um can be better by [14:03] finding this out and making suggestions to Claude already. So, this is uh something that we are going to work on during the beta phase of our AI AI agent support. Use compiler optimized functions. [14:18] Uh import all [14:30] good English explanation, but um the machine should find out what is necessary. [14:45] here everything that's imported and um it's now re-running and um it's now re-running the Tighten ways run command again. And we will see what an improvement this helps with. So, this is amazing. So, [14:59] this is from 650 milliseconds to 340 milliseconds. alone. So, what I would have expected is that [15:11] um Claude finds this out itself um Claude finds this out itself um based on the output of the core graph. Um but since it's not doing that we I'm going to need to adjust the [15:26] make a hint to Claude that this can be optimized. let's run tight ways. [15:51] Run PHP complex PHP again and look for again and look for optimization. [16:03] Optimizations in JSON logic all over again. um not looking at what's left but we want [16:17] want to see if there are more optimizations it can find and improve Uh, usually if you have a few performance optimizations that take a lot of time then uh, you are really blinded by this [16:32] unless you fix them and then look at the profiling data again you can't uh, see profiling data again you can't uh, see the performance problem uh, before so it's an iterative step of fixing and fixing more. [16:48] stands out triple array key first per logic node in apply. So this happens because we inlined the array key first things and now it can just reuse them. So inline all three into apply directly [17:02] one array key first zero method dispatches for the hot pass. Then get values has 291 calls most of that is overhead the method itself does very little get the key get logic up optionally wrap in array [17:16] all avoidable by inlining. So, this is something I've shown in the video myself Inlining uh code in PHP, inlining functions makes a lot of sense in the hot path, specifically if you have calls um in the [17:32] specifically if you have calls um in the 100,000s and more. [17:44] let's um just do all the um optimizations. [17:57] them suggested here. Then, it reruns um tight base run PHP complex PHP, and you can see there's another reduction from 326 milliseconds to 250 milliseconds. [18:09] 326 milliseconds to 250 milliseconds. From the original 90s uh 968, we are now at a 78% total reduction. [18:21] and it's quite amazing that it does this uh on a library that I don't know, and um it can make all these changes uh based on the profiling data. [18:34] Combining cloud code with the tight base CLI allows you to do performance optimizations of PHP code. As you've seen, we are still very early. It can detect problems and uh optimize quite a bit on its own already, but it would [18:49] also be helpful if we um add some additional hints and uh from the performance knowledge that we uh already have, and that is something that we are going to add through skills and additional things in the next [19:04] versions of the support. If you want to test this, we would be very happy getting in contact with you. You can enable the AI agent beta support in your Tight base organization through the beta feature section and then [19:19] use the Tight base run command to do the same that I did in this video. If you want to follow along for more PHP performance topics, please subscribe to newsletter. The link is in the description. Bye.