<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://shazwazza.com/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Shazwazza</title>
    <link>https://shazwazza.com/</link>
    <description>My blog which is pretty much just all about coding</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <image>
      <url>/media/0libq25y/frog.png?rmode=max&amp;v=1da0e911f4e6890</url>
      <title>Shazwazza</title>
      <link>https://shazwazza.com/</link>
    </image>
    <item>
      <guid isPermaLink="false">1336</guid>
      <link>https://shazwazza.com/post/letting-ai-agents-loose-on-examine/</link>
      <category>Examine</category>
      <title>Letting AI agents loose on Examine</title>
      <description>&lt;p&gt;I've been maintaining &lt;a href="https://github.com/Shazwazza/Examine"&gt;Examine&lt;/a&gt; for a very long time now. It's the search and indexing library that sits underneath every Umbraco site, and like any project that's been around long enough, it has plenty of hot paths that could be faster, a steady trickle of issues that need triaging, and a backlog of &amp;quot;I'll get to that eventually&amp;quot; performance work that, well… I never actually get to.&lt;/p&gt;
&lt;p&gt;So a couple of months ago I thought I'd try an experiment - what if I stopped doing all of that myself and instead let a bunch of AI agents do it for me, on a schedule, while I got on with everything else? This post is about how that went. I've shipped a few releases off the back of it and some of the hot-path improvements are genuinely a bit ridiculous.&lt;/p&gt;
&lt;h2 id="so-what-are-these-agentic-workflows"&gt;So what are these &amp;quot;agentic workflows&amp;quot;?&lt;/h2&gt;
&lt;p&gt;The thing I installed is &lt;a href="https://github.com/githubnext/agentics"&gt;GitHub Next's Agentic Workflows&lt;/a&gt; - a set of markdown-defined workflows that run in GitHub Actions and drive an AI agent to do actual maintenance work on your repo. They're not chat bots. They run on a schedule, they have persistent memory, they open real pull requests, and they leave the &amp;quot;should this ship?&amp;quot; decision to me.&lt;/p&gt;
&lt;p&gt;I ended up with a few of them running on Examine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Perf Improver&lt;/strong&gt; - runs daily, hunts for performance bottlenecks, writes benchmarks to actually prove the improvement, and opens a draft PR with the before/after numbers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Efficiency Improver&lt;/strong&gt; - its scrappier sibling, focused on the smaller allocation-and-LINQ-state-machine wins that add up over time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Daily Issue Triage&lt;/strong&gt; - goes through untriaged issues, sets types, applies labels, spots duplicates, and leaves a tidy triage report for me.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agentic Maintenance&lt;/strong&gt; - keeps the whole setup ticking along.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each one is just a markdown file in &lt;code&gt;.github/workflows/&lt;/code&gt; with a description, a schedule, some &lt;code&gt;safe-outputs&lt;/code&gt; limits (things like &amp;quot;you may open at most 4 PRs per run, and they must be drafts&amp;quot;) and a big prompt describing how to behave. That's it. The nice part is that the guardrails are declarative, so the agent can't merge its own PRs, it can't touch protected files, and it can only comment so many times per run. All of that is baked in.&lt;/p&gt;
&lt;h2 id="how-it-actually-works-day-to-day"&gt;How it actually works day to day&lt;/h2&gt;
&lt;p&gt;The bit that makes this more than a gimmick is the persistent memory. Every run, the Perf Improver reads its own notes - which build/test/benchmark commands it validated, what's on its optimisation backlog, what it worked on last time, and which suggestions I've already ticked off. Then it does a couple of tasks in a round-robin fashion so it's not endlessly poking at the same corner of the codebase.&lt;/p&gt;
&lt;p&gt;It also keeps a single rolling &amp;quot;Monthly Activity&amp;quot; issue open with a checklist of what needs my attention. So my side of it is pretty simple: the agent opens a draft PR with measured before/after numbers, I read it and run CI, and if I'm happy with it I merge. That's the whole loop. I'm the reviewer, the agent is the workhorse doing the grind I never had time for.&lt;/p&gt;
&lt;h2 id="so-what-did-they-actually-get-done"&gt;So what did they actually get done?&lt;/h2&gt;
&lt;p&gt;Over roughly the last two months, here's what these workflows actually got up to on Examine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;124&lt;/strong&gt; successful Perf Improver runs and &lt;strong&gt;9&lt;/strong&gt; successful Efficiency Improver runs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;20&lt;/strong&gt; successful Daily Issue Triage runs quietly keeping the issue tracker tidy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;24&lt;/strong&gt; performance/efficiency PRs reviewed and merged (13 from Perf Improver, 11 from Efficiency Improver) between late May and the end of June&lt;/li&gt;
&lt;li&gt;And the bit that actually matters - &lt;strong&gt;three releases shipped&lt;/strong&gt; off this work: &lt;strong&gt;v3.8.0&lt;/strong&gt;, &lt;strong&gt;v3.9.0&lt;/strong&gt; and the &lt;strong&gt;v4.0.0-beta.7&lt;/strong&gt; pre-release&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last point is really the whole thing. This isn't a pile of speculative branches rotting in a fork somewhere - it's code that went through my review, passed CI, and is now sitting in NuGet packages that real Umbraco sites are running.&lt;/p&gt;
&lt;h2 id="show-me-the-numbers"&gt;Show me the numbers&lt;/h2&gt;
&lt;p&gt;Right, this is the part I actually get excited about. One of my favourite things about the Perf Improver is that its prompt tells it to only attempt improvements it can actually measure - establish a baseline first, make the change, then measure again and document both numbers. For the algorithmic hot-path stuff that means benchmarks, so along the way it built out a proper &lt;a href="https://benchmarkdotnet.org/"&gt;BenchmarkDotNet&lt;/a&gt; suite that compares the current source against the published NuGet packages (3.0.1 through 3.3.0), which means I can show you real, reproducible deltas instead of hand waving.&lt;/p&gt;
&lt;h3 id="the-full-text-search-hot-path"&gt;The full-text search hot path&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ManagedQuery&lt;/code&gt; is &lt;em&gt;the&lt;/em&gt; primary full-text search entry point in Examine - it's what runs on basically every search. The agent noticed it had no dedicated benchmark, wrote one, and then stacked up a series of small, individually measured changes: a volatile factory cache in &lt;code&gt;SearchContext.GetFieldValueType&lt;/code&gt;, an early return in the extract-terms check, and killing off some redundant &lt;code&gt;ConcurrentDictionary&lt;/code&gt; lookups in &lt;code&gt;AddDocument&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here's the current source vs the most recent 3.3.0 release, on a 1,000-document index:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Mean&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ManagedQueryAllFields&lt;/td&gt;
&lt;td&gt;3.3.0&lt;/td&gt;
&lt;td style="text-align: right;"&gt;11.42 ms&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1,323 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ManagedQueryAllFields&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;2.17 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;371 KB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That's about &lt;strong&gt;5.3x faster&lt;/strong&gt; and roughly &lt;strong&gt;3.6x less memory allocated&lt;/strong&gt; on the single most travelled code path in the whole library. On the busiest thing Examine does. I'll happily take that.&lt;/p&gt;
&lt;h3 id="building-queries"&gt;Building queries&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;GroupedAnd&lt;/code&gt; / &lt;code&gt;GroupedOr&lt;/code&gt; / &lt;code&gt;GroupedNot&lt;/code&gt; are the workhorses of the query builder. A little &lt;code&gt;string[]&lt;/code&gt; fast-path (skipping a defensive &lt;code&gt;.ToArray()&lt;/code&gt; copy when the caller already handed it a &lt;code&gt;string[]&lt;/code&gt;) plus some allocation trimming got this:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Mean&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CreateQueryOnly&lt;/td&gt;
&lt;td&gt;3.3.0&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3,995 ns&lt;/td&gt;
&lt;td style="text-align: right;"&gt;8.34 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CreateQueryOnly&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;319 ns&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;2.20 KB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GroupedAndStringArray&lt;/td&gt;
&lt;td&gt;3.3.0&lt;/td&gt;
&lt;td style="text-align: right;"&gt;21,377 ns&lt;/td&gt;
&lt;td style="text-align: right;"&gt;21.10 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GroupedAndStringArray&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;16,659 ns&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;14.34 KB&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;CreateQuery()&lt;/code&gt; baseline dropping from 8.34 KB down to 2.2 KB is a lovely little win, and the grouped clauses are about 25% faster with a third of the allocation shaved off.&lt;/p&gt;
&lt;h3 id="constructing-a-valueset"&gt;Constructing a ValueSet&lt;/h3&gt;
&lt;p&gt;Every single document you index goes through a &lt;code&gt;ValueSet&lt;/code&gt; constructor. The old path allocated an intermediate dictionary and a generator state machine per field, which is exactly the kind of thing you don't notice until you're bulk indexing a big site. The agent got rid of both:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Mean&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Allocated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FromDictionary5Fields&lt;/td&gt;
&lt;td&gt;3.3.0&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1,183 ns&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2,200 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FromDictionary5Fields&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;226 ns&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;592 B&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FromDictionary20Fields&lt;/td&gt;
&lt;td&gt;3.3.0&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4,007 ns&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6,544 B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FromDictionary20Fields&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Source&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;654 ns&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;1,520 B&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That's roughly &lt;strong&gt;5-6x faster&lt;/strong&gt; and about &lt;strong&gt;4x less allocated&lt;/strong&gt; on indexing, and when you're rebuilding the index on a large Umbraco site that adds up fast.&lt;/p&gt;
&lt;p&gt;The really nice touch is that these benchmark result tables now live in &lt;code&gt;&amp;lt;remarks&amp;gt;&lt;/code&gt; doc-comments right next to the benchmark code, so the numbers are versioned in the repo alongside the thing they measure. The agent did that bit too.&lt;/p&gt;
&lt;h2 id="was-it-actually-worth-it"&gt;Was it actually worth it?&lt;/h2&gt;
&lt;p&gt;For me the thing that makes it work is the measurement. Everything comes to me as a small, focused, draft PR with the numbers attached, so I can look at it, sanity check it, run CI, and decide in a couple of minutes. It's not zero effort - I still read every change before it goes anywhere near main - but the ratio is fantastic. I'm getting a steady stream of well-measured, single-purpose performance PRs on a library I care about, on paths I'd genuinely never have found the time to optimise by hand, and I've shipped real releases because of it. For a project I maintain around everything else, that's a pretty great deal.&lt;/p&gt;
&lt;p&gt;If you maintain a repo with a backlog you never get to, especially performance work that needs benchmarks to justify it, I'd recommend giving &lt;a href="https://github.com/githubnext/agentics"&gt;GitHub Next's agentics&lt;/a&gt; a go.&lt;/p&gt;
&lt;p&gt;You can see all of it out in the open on the &lt;a href="https://github.com/Shazwazza/Examine"&gt;Examine repo&lt;/a&gt; - the &lt;code&gt;[perf-improver]&lt;/code&gt; and &lt;code&gt;[efficiency-improver]&lt;/code&gt; PRs, the benchmark suite, and the releases they fed into. And there's a nice bonus here for me too: &lt;a href="https://examinex.online/"&gt;ExamineX&lt;/a&gt;, my managed, cloud-hosted Examine search offering, runs on this exact same internal plumbing. So all this work the agents have been doing to tighten up Examine's query and indexing hot paths feeds straight through into ExamineX - the underlying engine gets faster and leaner, and every ExamineX site gets those wins for free without changing a thing. If you'd rather have your search running as a managed service instead of hosting Lucene indexes on your own servers, that's what ExamineX is there for. 🙂&lt;/p&gt;
</description>
      <pubDate>Fri, 03 Jul 2026 17:45:20 Z</pubDate>
      <a10:updated>2026-07-03T17:45:20Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1231</guid>
      <link>https://shazwazza.com/post/benchmarking-performance-of-your-code-between-release-versions/</link>
      <category>ASP.Net</category>
      <title>Benchmarking performance of your code between release versions</title>
      <description>&lt;p&gt;A while ago in 2016 I posted a &lt;a rel="noopener" href="https://github.com/dotnet/BenchmarkDotNet/issues/290" target="_blank"&gt;question&lt;/a&gt; on the &lt;a rel="noopener" href="https://github.com/dotnet/BenchmarkDotNet" target="_blank"&gt;BenchmarkDotNet&lt;/a&gt; repository about an official way to run benchmarks between Nuget releases. In 2018 I managed to find some time and with the with the help of &lt;a rel="noopener" href="https://github.com/adamsitnik" target="_blank"&gt;Adam Sitnik&lt;/a&gt; (one of the project’s maintainers), was able to &lt;a rel="noopener" href="https://github.com/dotnet/BenchmarkDotNet/pull/922" target="_blank"&gt;make that work&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I won’t go into detail about what BenchmarkDotNet is, but it’s a brilliant way to accurately run benchmarks against your code to see how it performs, how much memory is being used, etc…&lt;/p&gt;
&lt;p&gt;With this new feature you can now easily see how your code changes effect performance between your releases.&lt;/p&gt;
&lt;h2&gt;Show me the code&lt;/h2&gt;
&lt;p&gt;Making this work is quite easy and there’s a &lt;a rel="noopener" href="https://github.com/dotnet/BenchmarkDotNet/blob/master/samples/BenchmarkDotNet.Samples/IntroNuGet.cs" target="_blank"&gt;quick start code snippet&lt;/a&gt; in the repo already. For the example below I’ll use &lt;a rel="noopener" href="https://sixlabors.com/projects/imagesharp/" target="_blank"&gt;ImageSharp&lt;/a&gt; as the library to be tested and we’ll see how well &lt;a rel="noopener" href="https://twitter.com/James_M_South" target="_blank"&gt;James&lt;/a&gt; and his team is doing with regards to improving it’s JPEG decoding performance.&lt;/p&gt;
&lt;pre class="lang-csharp"&gt;&lt;code&gt;
[Config(typeof(Config))]
public class ImageTests
{
    private static readonly string _filePath = @"C:\temp\test.jpg";

    private class Config : ManualConfig
    {
        public Config()
        {
            var baseJob = Job.MediumRun.With(CsProjCoreToolchain.Current.Value);
            Add(baseJob.WithNuGet("SixLabors.ImageSharp", "1.0.0-beta0006").WithId("1.0.0-beta0006"));
            Add(baseJob.WithNuGet("SixLabors.ImageSharp", "1.0.0-beta0005").WithId("1.0.0-beta0005"));
            Add(baseJob.WithNuGet("SixLabors.ImageSharp", "1.0.0-beta0004").WithId("1.0.0-beta0004"));
        }
    }

    [Benchmark]
    public Size LoadJpg()
    {
        using (var img = Image.Load(_filePath))
        {
            var size = img.Size();
            return size;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above should seem pretty straightforward. It’s just setting up 3 BenchmarkDotNet jobs, each using a different version of the SixLabors.ImageSharp Nuget package. Then the actual benchmark test is loading in a JPEG extracting it’s size and returning it.&lt;/p&gt;
&lt;p&gt;Running the benchmark is like running any other BenchmarkDotNet test, for example in a console app:&lt;/p&gt;
&lt;pre class="lang-csharp"&gt;&lt;code&gt;
class Program
{
    static void Main(string[] args)
    {   
        var summary = BenchmarkRunner.Run();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The results&lt;/h2&gt;
&lt;table border="0"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;NuGetReferences&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LoadJpg&lt;/td&gt;
&lt;td&gt;1.0.0-beta0004&lt;/td&gt;
&lt;td&gt;SixLabors.ImageSharp 1.0.0-beta0004&lt;/td&gt;
&lt;td&gt;297.5 ms&lt;/td&gt;
&lt;td&gt;142.8 ms&lt;/td&gt;
&lt;td&gt;7.827 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoadJpg&lt;/td&gt;
&lt;td&gt;1.0.0-beta0005&lt;/td&gt;
&lt;td&gt;SixLabors.ImageSharp 1.0.0-beta0005&lt;/td&gt;
&lt;td&gt;202.9 ms&lt;/td&gt;
&lt;td&gt;466.6 ms&lt;/td&gt;
&lt;td&gt;25.577 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoadJpg&lt;/td&gt;
&lt;td&gt;1.0.0-beta0006&lt;/td&gt;
&lt;td&gt;SixLabors.ImageSharp 1.0.0-beta0006&lt;/td&gt;
&lt;td&gt;148.8 ms&lt;/td&gt;
&lt;td&gt;107.8 ms&lt;/td&gt;
&lt;td&gt;5.910 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Looks good! from the beta0004 release to the beta0006 release there’s almost twice the performance boost.&lt;/p&gt;
&lt;h2&gt;API Surface Area&lt;/h2&gt;
&lt;p&gt;There is one caveat though… In order to run these tests between versions of your library, the same API surface area will need to exist otherwise you’ll get exceptions when running the benchmarks. This is the reason why versions beta0001 –&amp;gt; beta0003 are not included in the jobs listed above. Its because in the older versions either the APIs were different or the namespaces were different.&lt;/p&gt;
&lt;p&gt;It is possible to work around this but you’d need to use some ugly reflection to do it and then you need to be careful that you are not testing the reflection performance hit either.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now you should have a pretty easy way to know how the performance of your library is changing between versions. Happy coding!&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:09:17 Z</pubDate>
      <a10:updated>2023-03-23T15:09:17Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1192</guid>
      <link>https://shazwazza.com/post/umbraco-41-benchmarks-part-2-back-office-database-queries/</link>
      <category>Umbraco</category>
      <title>Umbraco 4.1 Benchmarks Part 2 (Back Office Database Queries)</title>
      <description>&lt;div class="imported-post"&gt;This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.&lt;/div&gt;This is part 2 in a series of Umbraco 4.1 benchmarks created by various members of the core team in the lead up to launch. See &lt;a href="http://farmcode.org/post/2010/04/19/Umbraco-41-Benchmarks-Part-1-%28Do-Over%29.aspx"&gt;Part 1 here&lt;/a&gt; on request/response peformance in the Umbraco back office.  &lt;p&gt;This benchmark report looks at the data layer improvements in 4.1 by comparing query counts in 4.1 to 4.0.3. Not only has the data layer improved but there’s been significant improvements in the consumption of the data layer API made by many of the 4.1 pages and controls.&lt;/p&gt; &lt;p&gt;The stats below are represented as a percentage of the total calls of 4.0.3 where the number of queries in 4.0.3 are 100% and the number of queries in 4.1 are a percentage in relation to this. These results are based on the procedures listed at the bottom of this post and on averages run over 3 separate trials.&lt;/p&gt; &lt;style&gt;


















.stats th {background-color:#ffffcc;color:black;}
.stats td, .stats th {
border-top:solid 1px black;
border-right:solid 1px black;
border-top:solid 1px black;
}
.stats td.first, .stats th.first {
border-left:solid 1px black;
}
.stats tr.bottom td, .stats td.bottom {
border-bottom:solid 1px black;
}
.stats tr.one { background-color:#ededed;}
.stats tr.two { background-color:#dcdcdc;}
.stats tr.three { background-color:#ededed;}
.stats tr.four {background-color:#d6f5f5;}&lt;/style&gt;  &lt;table class="stats" cellspacing="0" cellpadding="2" width="470"&gt; &lt;tbody&gt; &lt;tr class="one"&gt; &lt;th class="first" valign="top" width="326"&gt;Step&lt;/td&gt; &lt;/th&gt; &lt;th valign="top" width="72"&gt;4.0.3&lt;/td&gt; &lt;/th&gt; &lt;th valign="top" width="70"&gt;4.1.0&lt;/td&gt; &lt;/tr&gt;&lt;/th&gt;&lt;/tr&gt; &lt;tr class="two"&gt; &lt;td class="first" valign="top" width="326"&gt;Login&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;68%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="one"&gt; &lt;td class="first" valign="top" width="326"&gt;Expand all Content nodes&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;23%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="one"&gt; &lt;td class="first" valign="top" width="326"&gt;Edit Home node&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;49%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="two"&gt; &lt;td class="first" valign="top" width="326"&gt;Publishing Home node&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;55%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="one"&gt; &lt;td class="first" valign="top" width="326"&gt;Edit About Umbraco node&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;49%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="two"&gt; &lt;td class="first" valign="top" width="326"&gt;Go to Settings App&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;100%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="one"&gt; &lt;td class="first" valign="top" width="326"&gt;Expand Document types tree&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;100%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="two"&gt; &lt;td class="first" valign="top" width="326"&gt;Edit Home document type&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;61%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="one"&gt; &lt;td class="first" valign="top" width="326"&gt;Save Home document type&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;67%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="two"&gt; &lt;td class="first" valign="top" width="326"&gt;Go to Media app&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;50%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="one"&gt; &lt;td class="first" valign="top" width="326"&gt;Create new folder labeled ‘Test’&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;88%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="two"&gt; &lt;td class="first" valign="top" width="326"&gt;Create new image under new ‘Test’ folder labeled ‘test1’&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;64%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="one"&gt; &lt;td class="first" valign="top" width="326"&gt;Upload new image file to ‘test1’ and save the node&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;49%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="two"&gt; &lt;td class="first" valign="top" width="326"&gt;Go to Content app (and in the case of 4.0.3, expand the tree and select the About Umbraco node since in 4.1 this will already be selected and loaded)&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;41%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="one"&gt; &lt;td class="first" valign="top" width="326"&gt;Edit Home node&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;43%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="two"&gt; &lt;td class="first" valign="top" width="326"&gt;Add ‘test1’ image to the ‘Text’ WYSIWYG property with the image picker and Publish node&lt;/td&gt; &lt;td class="first" valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;49%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="four"&gt; &lt;td class="first" valign="top" width="326"&gt;Average of averages above&lt;/td&gt; &lt;td valign="top" width="72"&gt;&amp;nbsp;&lt;/td&gt; &lt;td valign="top" width="70"&gt;60%&lt;/td&gt;&lt;/tr&gt; &lt;tr class="four bottom"&gt; &lt;td class="first" valign="top" width="326"&gt;Complete run through of the above steps&lt;/td&gt; &lt;td valign="top" width="72"&gt;100%&lt;/td&gt; &lt;td valign="top" width="70"&gt;66%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;So based on averages, Umbraco 4.1 is looking to have around &lt;font size="4"&gt;&lt;strong&gt;40% less&lt;/strong&gt; &lt;/font&gt;queries made than 4.0.3!!! Thats HUGE! &lt;/p&gt; &lt;p&gt;The following steps were taken on each trial of the above steps:&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;New instances of both 4.0.3 and 4.1  &lt;li&gt;Install CWS package on both instances  &lt;li&gt;Log out of both instances  &lt;li&gt;Bump web.config for both instances (clear out all data cache)  &lt;li&gt;Use SQL Profiler to determine query counts for each step listed above &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Also, SQL debugging has been added to 4.1 for MS SQL instances. If you compile the source in Debug mode you can get the SQL command output by adding a trace listener to your web.config. Underneath the configuration node you can add this xml block:&lt;/p&gt;&lt;pre&gt;&amp;lt;system.diagnostics&amp;gt;
	&amp;lt;trace autoflush="true"&amp;gt;
	  &amp;lt;listeners&amp;gt;
		&amp;lt;add name="SqlListener" 
			type="System.Diagnostics.TextWriterTraceListener" 
			initializeData="trace.log" /&amp;gt;
	  &amp;lt;/listeners&amp;gt;
	&amp;lt;/trace&amp;gt;
&amp;lt;/system.diagnostics&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This will create a trace.log file in the root of your web app SQL debugging.&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:14 Z</pubDate>
      <a10:updated>2023-03-23T15:08:14Z</a10:updated>
    </item>
  </channel>
</rss>