From 9321615969c23076c3bb0c7c08decf2b69716871 Mon Sep 17 00:00:00 2001 From: Tim Pilius Date: Sat, 13 Jul 2024 11:33:17 -0400 Subject: [PATCH] Adding a check to make sure that the benchmark workload is larger than the system's total memory. Will display a warning to the user when the workload is too small --- SteamPrefill.sln.DotSettings | 1 + .../CliCommands/Benchmark/BenchmarkModels.cs | 16 +--- .../Extensions/SystemMemoryMetrics.cs | 23 ++++++ SteamPrefill/Properties/GlobalUsings.cs | 1 + SteamPrefill/SteamManager.cs | 51 ++++++++++++- .../detailed-command-usage/Benchmark.md | 74 +++++++++++-------- .../detailed-command-usage/Select-Apps.md | 18 +++-- .../casts/benchmark-setup.cast | 8 +- docs/mkdocs/install-guides/Scheduled-Job.md | 7 +- 9 files changed, 138 insertions(+), 61 deletions(-) create mode 100644 SteamPrefill/Extensions/SystemMemoryMetrics.cs diff --git a/SteamPrefill.sln.DotSettings b/SteamPrefill.sln.DotSettings index 488e7ead..125b90bf 100644 --- a/SteamPrefill.sln.DotSettings +++ b/SteamPrefill.sln.DotSettings @@ -27,6 +27,7 @@ True True True + True True diff --git a/SteamPrefill/CliCommands/Benchmark/BenchmarkModels.cs b/SteamPrefill/CliCommands/Benchmark/BenchmarkModels.cs index 7cad9777..0af882a1 100644 --- a/SteamPrefill/CliCommands/Benchmark/BenchmarkModels.cs +++ b/SteamPrefill/CliCommands/Benchmark/BenchmarkModels.cs @@ -15,18 +15,9 @@ public sealed class BenchmarkWorkload public List AllQueuedRequests => QueuedAppsList.SelectMany(e => e.QueuedRequests).ToList(); - private ByteSize? _totalDownloadSize; - public ByteSize TotalDownloadSize - { - get - { - if (_totalDownloadSize == null) - { - _totalDownloadSize = ByteSize.FromBytes(QueuedAppsList.Sum(e => e.TotalBytes)); - } - return _totalDownloadSize.Value; - } - } + private ByteSize _totalDownloadSize; + public ByteSize TotalDownloadSize => _totalDownloadSize; + public string TotalDownloadSizeFormatted => _totalDownloadSize.ToDecimalString(); public long TotalFiles => QueuedAppsList.Sum(e => e.FileCount); public string TotalFilesFormatted => TotalFiles.ToString("n0"); @@ -43,6 +34,7 @@ public ByteSize TotalDownloadSize public BenchmarkWorkload(ConcurrentBag queuedAppsList, ConcurrentStack cdnServers) { QueuedAppsList = queuedAppsList; + _totalDownloadSize = ByteSize.FromBytes(QueuedAppsList.Sum(e => e.TotalBytes)); ServerShimList = cdnServers.Select(e => _mapper.Map(e)).ToList(); } diff --git a/SteamPrefill/Extensions/SystemMemoryMetrics.cs b/SteamPrefill/Extensions/SystemMemoryMetrics.cs new file mode 100644 index 00000000..ae684419 --- /dev/null +++ b/SteamPrefill/Extensions/SystemMemoryMetrics.cs @@ -0,0 +1,23 @@ +namespace SteamPrefill.Extensions +{ + public static class SystemMemoryMetrics + { + public static ByteSize GetTotalSystemMemory() + { + var info = new ProcessStartInfo("free -m") + { + FileName = "/bin/bash", + Arguments = "-c \"free -m\"", + RedirectStandardOutput = true + }; + + using var process = Process.Start(info); + var output = process.StandardOutput.ReadToEnd(); + + var lines = output.Split("\n"); + var memory = lines[1].Split(" ", StringSplitOptions.RemoveEmptyEntries); + + return ByteSize.FromBytes(double.Parse(memory[1]) * ByteSize.FromMebiBytes(1).Bytes); + } + } +} \ No newline at end of file diff --git a/SteamPrefill/Properties/GlobalUsings.cs b/SteamPrefill/Properties/GlobalUsings.cs index 0c6b5076..10b9ec4a 100644 --- a/SteamPrefill/Properties/GlobalUsings.cs +++ b/SteamPrefill/Properties/GlobalUsings.cs @@ -36,6 +36,7 @@ global using System.Linq; global using System.Net; global using System.Net.Http; +global using System.Runtime.InteropServices; global using System.Threading; global using System.Text.Json; global using System.Text.Json.Serialization; diff --git a/SteamPrefill/SteamManager.cs b/SteamPrefill/SteamManager.cs index fdee3877..f95db7cd 100644 --- a/SteamPrefill/SteamManager.cs +++ b/SteamPrefill/SteamManager.cs @@ -255,10 +255,55 @@ public async Task SetupBenchmarkAsync(List appIds, bool useAllOwnedGames, // Writing stats benchmarkWorkload.PrintSummary(_ansiConsole); - var fileSize = ByteSize.FromBytes(new FileInfo(AppConfig.BenchmarkWorkloadPath).Length); + CheckBenchmarkWorkloadSize(benchmarkWorkload); + _ansiConsole.Write(new Rule()); _ansiConsole.LogMarkupLine("Completed build of workload file..."); - _ansiConsole.LogMarkupLine($"Resulting file size : {MediumPurple(fileSize.ToBinaryString())}"); + } + + //TODO document + private static void CheckBenchmarkWorkloadSize(BenchmarkWorkload generatedWorkload) + { + // While technically you can run a benchmark from a client Linux machine, this scenario is probably pretty rare since most people + // run SteamPrefill on the cache host. Rather than add some more complexity by checking that the benchmark is definitely being created + // on the cache host, we'll omit it and save some added complexity + if (!System.OperatingSystem.IsLinux()) + { + return; + } + + var systemMemory = SystemMemoryMetrics.GetTotalSystemMemory(); + // If the user generated a workload that is larger than the system's total memory, then the benchmark will always be reading from disk. + if (generatedWorkload.TotalDownloadSize > systemMemory) + { + return; + } + + // Table setup + var table = new Table + { + ShowHeaders = false, + Border = TableBorder.Rounded, + BorderStyle = new Style(SpectreColors.LightYellow) + }; + table.AddColumn(""); + + // Adding message rows + table.AddRow(LightYellow($"{new string(' ', 40)}!!!!!! Warning !!!!!!")); + table.AddEmptyRow(); + table.AddRow($"The generated workload size of {Magenta(generatedWorkload.TotalDownloadSizeFormatted)} " + + $"is smaller than the total system memory of {LightYellow(systemMemory.ToDecimalString())}."); + table.AddRow("Linux will cache files that it reads in system memory to improve performance of frequently used files,"); + table.AddRow("however this benchmark is typically used to test disk IO performance."); + table.AddRow("In order to guarantee that an accurate benchmark where files are only ever read from disk,"); + table.AddRow("the workload size should be larger than the system's memory."); + table.AddEmptyRow(); + table.AddRow($"Please create a new benchmark workload that is larger than {LightYellow(systemMemory.ToDecimalString())}."); + + + // Render the table to the console + AnsiConsole.Write(table); + AnsiConsole.WriteLine(); } //TODO this method is awfully complex, has lots and lots of nesting. Makes it a bit hard to read at a glance @@ -378,6 +423,7 @@ await _ansiConsole.CreateSpectreProgress().StartAsync(async ctx => _ansiConsole.Write(new Rule()); } + //TODO rename private IOrderedEnumerable> SortData(ConcurrentDictionary index, SortOrder sortOrder, SortColumn sortColumn) { if (sortOrder == SortOrder.Ascending) @@ -399,7 +445,6 @@ private IOrderedEnumerable> SortData(ConcurrentDi #endregion - public async Task> GetAllAvailableAppsAsync() { var ownedGameIds = _steam3.LicenseManager.AllOwnedAppIds; diff --git a/docs/mkdocs/detailed-command-usage/Benchmark.md b/docs/mkdocs/detailed-command-usage/Benchmark.md index 59fbfd9a..703f0097 100644 --- a/docs/mkdocs/detailed-command-usage/Benchmark.md +++ b/docs/mkdocs/detailed-command-usage/Benchmark.md @@ -2,58 +2,70 @@ ## Overview -Intended for use in identifying potential bottlenecks both server side (usually disk IO), as well as client side. +Intended for use in identifying potential Lancache bottlenecks, which is typically disk IO. Can be used both server side as well as client side. -`benchmark` uses the same download logic as `prefill`, however it offers the following instead: + +`benchmark` uses the same download logic as `prefill`, however it offers the following advantages instead: -- Portable, no need to login to Steam in order to start download. -- Able to be used across multiple machines at the same time, without logging in -- Continuous sustained download, combines multiple apps into a single download -- Repeatable, will perform the same download every time -- Randomized, requests will be completed in a random order ------ +- Portable, no need to login to Steam in order to start the benchmark. +- Able to be used across multiple machines at the same time, without logging in. +- Continuous sustained download, combines multiple apps into a single download. +- Repeatable, will perform the same download every time. +- Randomized, requests will be completed in a random order. + +The workflow for benchmarking is to setup a workload with the `setup` subcommand, which can be used as many times as desired with the `run` subcommand. + +--- ## setup -
+

-Creates a benchmark "workload" comprised of multiple apps, that will then be benchmarked using the `run` sub-command. Generally, the ideal benchmark will be the one that most closely matches the apps that you will usually be downloaded. This can be setup for example with `./SteamPrefill benchmark setup --use-selected` +Creates a benchmark "workload" comprised of multiple apps, that will then be benchmarked using the `run` sub-command. Generally, the ideal benchmark will be the one that most closely matches the apps that you will usually be downloaded. This can be setup for example with `./SteamPrefill benchmark setup --use-selected`. A benchmark can also be setup by specifying an individual game's appid (or more than one if desired), or by using one of the built in presets like `--preset SmallChunks` or `--preset LargeChunks` + +!!! Warning + This benchmark feature is typically used to test disk IO performance. Linux will cache files that it reads in system memory to improve performance of frequently used files. In order to guarantee that an accurate benchmark where files are only ever read from disk, the workload size needs to be larger than the Lancache server's total amount of memory. + +Once the workload has been generated, a summary with some stats will be displayed. The chunk size distribution will give you an idea of the performance characteristics of the workload you created. The ideal performance scenario is when the chunk sizes are primarily 1 MiB or larger, whereas the worst possible scenario is having them be on the small side. Note that there is nothing that you can do about the chunk sizes, these are the size that the chunks are stored on Steam's servers. The distribution is here just for the sake of visibility into what is being tested. + -| Option               | Values | | -| ---------------- | --- | --- | -| --use-selected | | Creates a workload file using apps previously specified with `select-apps`. Ideal for most use cases, since it likely aligns with games that will be downloaded by real event clients. | -| --all | | Benchmark workload will be created using all currently owned apps. | -| --appid | | The id of one or more apps to include in benchmark workload file. Useful for testing a specific app, without having to modify previously selected apps. AppIds can be found using [SteamDB](https://steamdb.info/) | -| --no-ansi | | Application output will be in plain text, rather than using the visually appealing colors and progress bars. Should only be used if terminal does not support Ansi Escape sequences, or when redirecting output to a file. | -| --preset | SmallChunks, LargeChunks | Can be used to quickly setup a benchmark with a predefined workload of differing characteristics. LargeChunks represents a best case scenario where chunk sizes are close to 1Mib, whereas SmallChunks is a worst case scenario of small files. | ------ + +| Option               | Values | | +| ------------------------------------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --use-selected | | Creates a workload file using apps previously specified with `select-apps`. Ideal for most use cases, since it likely aligns with games that will be downloaded by real event clients. | +| --all | | Benchmark workload will be created using all currently owned apps. | +| --appid | | The id of one or more apps to include in benchmark workload file. Useful for testing a specific app, without having to modify previously selected apps. AppIds can be found using [SteamDB](https://steamdb.info/) | +| --no-ansi | | Application output will be in plain text, rather than using the visually appealing colors and progress bars. Should only be used if terminal does not support Ansi Escape sequences, or when redirecting output to a file. | +| --preset | SmallChunks, LargeChunks | Can be used to quickly setup a benchmark with a predefined workload of differing characteristics. LargeChunks represents a best case scenario where chunk sizes are close to 1Mib, whereas SmallChunks is a worst case scenario of small files. | + +--- ## run -Runs multiple iterations of the benchmark workload created with `benchmark setup`. Useful for measuring the throughput for the Lancache server, and diagnosing any potential performance issues. +Runs multiple iterations of the benchmark workload created with `benchmark setup`. Useful for measuring the throughput for the Lancache server, and diagnosing any potential performance issues. ** Warmup **

-The first part of the benchmark run will be the initialization + warmup of the workload. The workload file previously created with `benchmark setup` will be loaded from disk, and the ordering of the requests to be made will be randomized. +The first part of the benchmark run will be the initialization + warmup of the workload. The workload file previously created with `benchmark setup` will be loaded from disk, and the ordering of the requests to be made will be randomized. Next, the warmup run will download all of the workload's requests, which is necessary for a few reasons: - It ensures that all of the data has been downloaded, and is cached by the Lancache. - Allows for data that has been cached in the server's memory to be flushed by the new requests, ensuring that we are testing disk I/O. -- Gives the CPU a chance to physically warm up, minimizing potential fluctuations between runs. +- Gives the CPU a chance to physically warm up, minimizing potential fluctuations between runs. ** Running ** -After the warmup, `benchmark run` will begin downloading the same workload in a loop, for as many iterations as specified with `--iterations` (default: 5). After each iteration, it will display the overall average download rate for that iteration. +After the warmup, `benchmark run` will begin downloading the same workload in a loop, for as many iterations as specified with `--iterations` (default: 5). After each iteration, it will display the overall average download rate for that iteration.

@@ -65,17 +77,17 @@ Once all the iterations have been completed, a summary table displaying the min/ ** Identifying bottlenecks ** -While `benchmark run` is useful for getting an overall idea of your server's performance, it won't however identify bottlenecks in the system by itself. It is instead primarily intended to be another tool to help with identifying bottlenecks, by providing a constant and even load on the server. +While `benchmark run` is useful for getting an overall idea of your server's performance, it won't however identify bottlenecks in the system by itself. It is instead primarily intended to be another tool to help with identifying bottlenecks, by providing a constant and even load on the server. -It is recommended that you run some sort of system monitoring software on the server while running your benchmarks, so that you can get an idea of how your server is handling the load. There are many monitoring tools available, such as [Glances](https://github.com/nicolargo/glances), that provide a visual overview of the system. +It is recommended that you run some sort of system monitoring software on the server while running your benchmarks, so that you can get an idea of how your server is handling the load. There are many monitoring tools available, such as [Glances](https://github.com/nicolargo/glances), that provide a visual overview of the system. -Two important measurements to keep an eye on, are the overall `CPU` usage, as well as `iowait`. The majority of bottlenecks for servers will be either the speed of the CPU, or the speed at which the disk(s) can read. +Two important measurements to keep an eye on, are the overall `CPU` usage, as well as `iowait`. The majority of bottlenecks for servers will be either the speed of the CPU, or the speed at which the disk(s) can read. ![benchmark-run-glances](images/benchmark-run-glances.png){: style="width:350px"} -| Option | | Values | Default | | -| ------------- | --- | ------------- | ------- | --- | -| --concurrency | -c | 1-100 | **30** | The maximum number of concurrent requests in flight at one time. A higher number may improve maximum throughput, but may possibly have a negative effect if the cache server cannot process the concurrent requests fast enough. | -| --iterations | -i | 1-25 | **5** | The number of runs to do before calculating overall results. | -| --unit | | bits, bytes | **bits** | Specifies which unit to use to display download speed. | -| --no-ansi | | | | Application output will be in plain text, rather than using the visually appealing colors and progress bars. Should only be used if terminal does not support Ansi Escape sequences, or when redirecting output to a file. | +| Option | | Values | Default | | +| ------------- | --- | ----------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --concurrency | -c | 1-100 | **30** | The maximum number of concurrent requests in flight at one time. A higher number may improve maximum throughput, but may possibly have a negative effect if the cache server cannot process the concurrent requests fast enough. | +| --iterations | -i | 1-25 | **5** | The number of runs to do before calculating overall results. | +| --unit | | bits, bytes | **bits** | Specifies which unit to use to display download speed. | +| --no-ansi | | | | Application output will be in plain text, rather than using the visually appealing colors and progress bars. Should only be used if terminal does not support Ansi Escape sequences, or when redirecting output to a file. | diff --git a/docs/mkdocs/detailed-command-usage/Select-Apps.md b/docs/mkdocs/detailed-command-usage/Select-Apps.md index a04efbd2..c6d21782 100644 --- a/docs/mkdocs/detailed-command-usage/Select-Apps.md +++ b/docs/mkdocs/detailed-command-usage/Select-Apps.md @@ -21,24 +21,26 @@ Lists all selected apps and their disk usage. ### Example usage Checking the `status` is as simple as running the following from the terminal: + ```powershell -./{{prefillName}} status +./{{prefill_name}} status ``` #### Customized the sorting An advanced usage with customized sorting can be used as the following from the terminal: + ```powershell -./{{prefillName}} status --sort-order descending --sort-column size +./{{prefill_name}} status --sort-order descending --sort-column size ``` ----- ### Options -| Option | | Values | Default | | -| --------------- | --- | --------------------- | ------------- | --- | -| --sort-order | | ascending, descending | **ascending** | Specifies which order the data should be sorted. | -| --sort-by | | app, size | **app** | Specifies which column should be used for the sorting. | -| --os | | windows, linux, macos | **windows** | Specifies which operating system(s) chunks should be filtered for. | -| --no-ansi | | | | Application output will be in plain text, rather than using the visually appealing colors and progress bars. Should only be used if terminal does not support Ansi Escape sequences, or when redirecting output to a file. | \ No newline at end of file +| Option | | Values | Default | | +| ------------ | --- | --------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| --sort-order | | ascending, descending | **ascending** | Specifies which order the data should be sorted. | +| --sort-by | | app, size | **app** | Specifies which column should be used for the sorting. | +| --os | | windows, linux, macos | **windows** | Specifies which operating system(s) chunks should be filtered for. | +| --no-ansi | | | | Application output will be in plain text, rather than using the visually appealing colors and progress bars. Should only be used if terminal does not support Ansi Escape sequences, or when redirecting output to a file. | diff --git a/docs/mkdocs/detailed-command-usage/casts/benchmark-setup.cast b/docs/mkdocs/detailed-command-usage/casts/benchmark-setup.cast index d86d051a..b87a09b1 100644 --- a/docs/mkdocs/detailed-command-usage/casts/benchmark-setup.cast +++ b/docs/mkdocs/detailed-command-usage/casts/benchmark-setup.cast @@ -166,10 +166,10 @@ [4.112799999999996,"o","\r\n"] [4.113799999999997,"o","────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────\r\n"] [4.134799999999998,"o"," \u001b[4;38;5;15mBenchmark workload summary\u001b[0m \r\n \r\n \u001b[38;5;80mApp\u001b[0m │ \u001b[38;5;15mId\u001b[0m │ \u001b[38;5;141mDownload Size\u001b[0m │ \u001b[38;5;229mTotal Chunks\u001b[0m │ \u001b[38;5;77mAverage Chunk Size\u001b[0m \r\n ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━┿━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━ \r\n Call of Duty®: Modern Warfare® II | Warzone™ 2.0 │ 1938090 │ 35.56 GiB │ 41,623 │ 895.91 KiB \r\n ━━━━━━━━━━━━━━━━━━━━━━━━━━"] -[4.134799999999998,"o","━━━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━┿━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━ \r\n │ │ \u001b[1;38;5;15m35.56 GiB\u001b[0m │ \u001b[1;38;5;15m41,623\u001b[0m │ \u001b[1;38;5;15m895.91 KiB\u001b[0m \r\n \r\n \u001b[4;38;5;15mRequest size distribution\u001b[0m \r\n \r\n 0 - 256 KiB \u001b[38;5;203m████████████ 3922\u001b[0m\u001b[38;5;8m \u001b[0m \r\n 256 - 512 KiB 978\u001b[38;"] +[4.134799999999998,"o","━━━━━━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━┿━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━ \r\n │ │ \u001b[1;38;5;15m35.56 GiB\u001b[0m │ \u001b[1;38;5;15m41,623\u001b[0m │ \u001b[1;38;5;15m895.91 KiB\u001b[0m \r\n \r\n \u001b[4;38;5;15mChunk size distribution\u001b[0m \r\n \r\n 0 - 256 KiB \u001b[38;5;203m████████████ 3922\u001b[0m\u001b[38;5;8m \u001b[0m \r\n 256 - 512 KiB 978\u001b[38;"] [4.134799999999998,"o","5;8m \u001b[0m \r\n 512 - 768 KiB 910\u001b[38;5;8m \u001b[0m \r\n 768 - 1 MiB ███████████████████████████████████████████████████████████████████████████████████████ 22281 \r\n 1024 - 1.25 MiB \u001b[38;5;77m███████████████████████████████████████████████████████ 13532\u001b[0m\u001b[38;5;8m \u001b[0m \r\n\r\n─────────────────────────────────────────────────────────────────────"] [4.134799999999998,"o","───────────────────────────────────────────────────\r\n[6:42:29 PM] Completed build of workload file...\r\n"] -[4.134799999999998,"o","[6:42:29 PM] Resulting file size : \u001b[38;5;141m2.06 MiB\u001b[0m\r\n"] +[4.134799999999998,"o",""] [4.135799999999997,"o","\u001b[?25l"] -[4.135799999999997,"o"," \r\n\u001b[38;5;2m⣾\u001b[0m Disconnecting\r\n \r\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[?25h"] -[4.135799999999997,"o","[6:42:29 PM] Disconnected from Steam!\r\n\u001b[?25l"] +[4.135799999999997,"o"," \r\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[?25h"] +[4.135799999999997,"o","[6:42:29 PM] Disconnected from Steam!\u001b[?25l"] diff --git a/docs/mkdocs/install-guides/Scheduled-Job.md b/docs/mkdocs/install-guides/Scheduled-Job.md index 417cc6bf..28cf0d24 100644 --- a/docs/mkdocs/install-guides/Scheduled-Job.md +++ b/docs/mkdocs/install-guides/Scheduled-Job.md @@ -1,7 +1,7 @@ # Configuring a Nightly Job !!! Note -This guide assumes that you have already installed **{{prefill_name}}** on your system. If you have not yet installed **{{prefill_name}}**, see [Linux Setup Guide](../Linux-Setup-Guide) + This guide assumes that you have already installed **{{prefill_name}}** on your system. If you have not yet installed **{{prefill_name}}**, see [Linux Setup Guide](../Linux-Setup-Guide) ## Configuring The Schedule @@ -29,11 +29,12 @@ WantedBy=timers.target ## Configuring The Job -Next, well setup the job that will be triggered nightly by the `timer` that we previously setup. Create a new file `/etc/systemd/system/{{prefill_name.lower()}}.service`, and save the following configuration into the file. +Next, we will setup the job that will be triggered nightly by the `timer` that we previously setup. Create a new file `/etc/systemd/system/{{prefill_name.lower()}}.service`, and save the following configuration into the file. !!! Note -The values of `User`, `WorkingDirectory`, and `ExecStart` will need to be configured to point to your **{{prefill_name}}** install location. + The values of `User`, `WorkingDirectory`, and `ExecStart` will need to be configured to point to your **{{prefill_name}}** install location. +#TODO the syntax highlighting here is absolutely awful ```ini [Unit] Description={{prefill_name}}