bench_lang_intro(3tcl)

πŸ’– bench_lang_intro β€” bestie's guide to the bench language πŸ’–

okay so this is bench_lang_intro, from the Benchmarking/Performance tools manual fam. welcome to the group chat, pull up a chair 🫢


✨ NAME ✨

bench_lang_intro β€” bench language introduction


🌸 DESCRIPTION 🌸

So this doc? It's the informal lil intro to version 1 of the bench language, and it teaches you by throwing a whole bunch of examples at you. Like, a multitude. After you read this, if you're a benchmark writer, you should be ready to actually understand the formal bench language specification. no cap πŸ’…

πŸŽ€ FUNDAMENTALS πŸŽ€

Broadest terms possible: the bench language is essentially Tcl, plus a bunch of commands that support declaring benchmarks. A document written in this language is a Tcl script and has the same syntax. that's it, that's the vibe ✨

πŸ¦‹ BASICS πŸ¦‹

One of the most simplest benchmarks you can write in bench is this:

bench -desc LABEL -body {
    set a b
}

This declares a benchmark named LABEL that measures how long it takes to assign a value to a variable. The Tcl code doing that assignment is the -body of the benchmark. iconic, honestly πŸ’–

πŸ’œ PRE- AND POSTPROCESSING πŸ’œ

Next example, and it's a glow-up: how to declare initialization and cleanup code. Like, code that computes info for the -body to use, and code that releases those resources after the measurement is done. Those are -pre and -post-body, respectively. 🧚

In our example β€” straight up drawn from the benchmark suite of Tcllib's aes package β€” the concrete initialization code constructs the key schedule used by the encryption command whose speed we're measuring, and the cleanup code releases any resources bound to that schedule.

bench -desc "AES-${len} ECB encryption core" -pre {
    set key [aes::Init ecb $k $i]
} -body {
    aes::Encrypt $key $p
} -post {
    aes::Final $key
}

πŸ”₯ ADVANCED PRE- AND POSTPROCESSING πŸ”₯

Last example, and again it's about initialization and cleanup code. To see how it differs from the regular init/cleanup from the last section, you gotta know a lil more about how bench actually measures the speed of the -body. πŸ•΅οΈ

So instead of running the -body just once, the system actually executes the -body several hundred times and then returns the average of the found execution times. Why? To remove environmental effects like machine load from the result as much as possible β€” outliers cancel each other out in the average. math queen behaviour πŸ’…

The drawback: when we measure operations that are not idempotent, we will most likely not measure the time for the operation we actually want. Instead we measure the time of the state(s) the system is in after the first iteration β€” a whole mixture of things we have zero interest in. 😭

Say we wanna measure the time it takes to include an element into a set, where the element isn't in the set yet, and the set has specific properties like being a shared Tcl_Obj. Then the first iteration measures the time for that. But every subsequent iteration measures the time to include an element that's already in the set, and the Tcl_Obj holding the set isn't shared anymore either. In the end, the timings from those several hundred iterations of that state overwhelm the time from the first iteration β€” the only one that actually measured what we wanted. πŸ’€

Enter the advanced initialization and cleanup codes: -ipre- and the -ipost- body, respectively. They exist to solve this exact problem. The regular init and cleanup codes run before and after the whole series of iterations, while the advanced codes run before and after each iteration of the body, without being measured themselves. That lets them bring the system into the exact state the body wishes to measure. periodt πŸ‘‘

Our example β€” straight up drawn from the benchmark suite of Tcllib's struct::set package β€” is for exactly the case we used above to show why advanced init/cleanup is necessary. Its concrete initialization code constructs a variable referring to a set with specific properties (the set has a string representation, which is shared) affecting the speed of the inclusion command, and the cleanup code releases the temporary variables created by this initialization. 🌈

bench -desc "set include, missing <SC> x$times $n" -ipre {
    set A $sx($times,$n)
    set B $A
} -body {
    struct::set include A x
} -ipost {
    unset A B
}

πŸ“š FURTHER READING πŸ“š

Now that you've digested this doc, you β€” the reader, assumed to be a writer of benchmarks β€” should be fortified enough to understand the formal bench language specfication. It'll also serve as the detailed specification and cheat sheet for all available commands and their syntax. iykyk πŸŽ€


πŸ› BUGS, IDEAS, FEEDBACK πŸ›

This document, and the package it describes, will undoubtedly contain bugs and other problems. please report such in the category bench of the Tcllib Trackers at [http://core.tcl.tk/tcllib/reportlist]. And also report any ideas for enhancements you may have for either the package and/or the documentation. we wanna hear it fr fr 🫢

When proposing code changes, please provide unified diffs, i.e. the output of diff -u.

Note further that attachments are strongly preferred over inlined patches. Attachments can be made by going to the Edit form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar. do it this way bestie πŸ’–

πŸ‘€ SEE ALSO πŸ‘€

  • bench_intro
  • bench_lang_spec

πŸ”‘ KEYWORDS πŸ”‘

bench language, benchmark, examples, performance, testing


🏷️ CATEGORY 🏷️

Benchmark tools


Copyright (c) 2007 Andreas Kupries <andreas_kupries@users.sourceforge.net>


okay that's the whole thing!! this page is from tcllib, version 1.0 β€” mwah, go write some benchmarks, you're gonna slay πŸ’…βœ¨πŸ¦‹πŸ’–

πŸ“¦ where this page comes from