# A micro-benchmark

**URL:** <https://racket.discourse.group/t/a-micro-benchmark/2347>\
**Category:** General\
**Created:** [September 28, 2023, 5:08pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347 "2023-09-28T17:08:30Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![lewisl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/lewisl/32/1321_2.png) [@lewisl](https://racket.discourse.group/u/lewisl)\
**Post date:** [October 4, 2023, 8:28pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/41 "2023-10-04T20:28:38Z")

</div>

Here's what gpt-4 says, based on using Racket docs as part of its copious training data:

```scheme
In Racket, you can use the #:result keyword with for/fold to give a hint to the compiler to unbox the 
accumulator variable when possible. This can help improve performance, especially in tight loops 
where you are working with flonum values.

Here's a simple example to demonstrate the use of #:result to unbox a flonum accumulator when 
summing an flvector:

racket
Copy code
#lang racket

(require racket/flonum)

(define (flvector-sum vec)
  (for/fold ([sum 0.0])
            #:result (flonum? sum) ; Hint for the compiler to unbox the accumulator
            ([val (in-flvector vec)])
    (fl+ sum val)))
In this example, the #:result (flonum? sum) tells the compiler that the accumulator, sum, should be a 
flonum, giving a hint that it can be unboxed for better performance.

It's worth noting that this is just a hint, and the compiler might choose not to unbox the accumulator in 
certain situations. However, for performance-critical loops with flonum values, it can provide a 
noticeable improvement.

```

It didn't quite provide the ideal hint as suggested above in the thread: `#:result (fl+ sum)`. Sparing you the copy/paste, gpt-4 acknowledge that this is even better because it gives 2 hints: that the type of sum is float and that the result of the fold/for loop is also float. Further, it "prefers" using the #:result argument vs putting fl+ at the start of a form that encloses the for/fold form because it keeps the loop in its more typical syntax and enables use of other for/fold named parameters. I agree.

Having been pointed to section 19 of the Guide, I have to say I would have never figure out the syntax for actually incorporating the hint in the code as no example is provided.

---

<div class="post-metadata">

**Author:** ![jryans](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jryans/32/31_2.png) [@jryans](https://racket.discourse.group/u/jryans)\
**Post date:** [October 4, 2023, 8:47pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/42 "2023-10-04T20:47:41Z")

</div>

> [@lewisl](#):
>
> Having been pointed to section 19 of the Guide, I have to say I would have never figure out the syntax for actually incorporating the hint in the code as no example is provided.

Perhaps a good moment for someone to contribute such an example then. I'm sure it would help the next docs reader understand what's going on more quickly.

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [October 4, 2023, 8:47pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/43 "2023-10-04T20:47:53Z")

</div>

That code doesn't work. It produces a boolean rather than the sum. Beware of plausible-sounding BS…

---

<div class="post-metadata">

**Author:** ![lewisl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/lewisl/32/1321_2.png) [@lewisl](https://racket.discourse.group/u/lewisl)\
**Post date:** [October 4, 2023, 8:48pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/44 "2023-10-04T20:48:49Z")

</div>

You are so right! Probably Chatgpt won't take that many jobs away if doing the job right matters!

---

<div class="post-metadata">

**Author:** ![lewisl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/lewisl/32/1321_2.png) [@lewisl](https://racket.discourse.group/u/lewisl)\
**Post date:** [October 4, 2023, 8:51pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/45 "2023-10-04T20:51:11Z")

</div>

what's the best way? seems like a (minor) contribution not a bug to report on GitHub with a PR.

---

<div class="post-metadata">

**Author:** ![jryans](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jryans/32/31_2.png) [@jryans](https://racket.discourse.group/u/jryans)\
**Post date:** [October 4, 2023, 9:09pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/46 "2023-10-04T21:09:17Z")

</div>

A PR is indeed likely the right way forward! There's even a ongoing [Racket summer event](https://racket.discourse.group/t/the-2023-racket-summer-event/2191) focused on examples as well. 🙂

In case you may not have encountered it yet, Racket docs will reveal their source path if you click on the section header. So for the [page](https://docs.racket-lang.org/guide/performance.html#%28part._fixnums%2Bflonums%29) mentioned above, you can see that the main document is [https://github.com/racket/racket/tree/master/pkgs/racket-doc/scribblings/guide/guide.scrbl](https://github.com/racket/racket/tree/master/pkgs/racket-doc/scribblings/guide/guide.scrbl), and then from there, a little searching / guessing reveals the part in question: [https://github.com/racket/racket/blob/e9376c099a53825ef31f233ca80f42641ebaa26a/pkgs/racket-doc/scribblings/guide/performance.scrbl#L365](https://github.com/racket/racket/blob/e9376c099a53825ef31f233ca80f42641ebaa26a/pkgs/racket-doc/scribblings/guide/performance.scrbl#L365)

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [October 5, 2023, 12:27pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/47 "2023-10-05T12:27:06Z")

</div>

Btw - the corresponding thread on the Julia forum show cases a really nifty benchmarking tool. Makes for a neat project idea.

 ![image](https://global.discourse-cdn.com/free1/uploads/racket/original/2X/2/20473bfedbd8c4ae5f547d5a00289b5a067e4cd7.png)

---

<div class="post-metadata">

**Author:** ![robby](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/robby/32/7_2.png) [@robby](https://racket.discourse.group/u/robby)\
**Post date:** [October 5, 2023, 1:22pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/48 "2023-10-05T13:22:31Z")

</div>

Woah that's really cool!

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [October 5, 2023, 1:47pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/49 "2023-10-05T13:47:38Z")

</div>

My personal favorite is hyperfine: [GitHub - sharkdp/hyperfine: A command-line benchmarking tool](https://github.com/sharkdp/hyperfine)

---

<div class="post-metadata">

**Author:** ![gus-massa](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/gus-massa/32/507_2.png) [@gus-massa](https://racket.discourse.group/u/gus-massa)\
**Post date:** [October 5, 2023, 2:48pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/50 "2023-10-05T14:48:54Z")

</div>

> [@lewisl](#):
>
> I didn't see Gus-massa's response anywhere except in your post. It certainly does work, almost a 3X speedup!!

My version is a small rewrite of the one posted before by @bogdan that has a similar speedup. My version is IMHO better as a hint to improve the compiler someday.

The idea is that flonums are usually stored in secret boxes.For example in `(vector (cons 1 2) 3.0)` the vector has a pointer to the object that represent the `pair` and a pointer to the secret box with a flonum `3.0`.

In this case, if you wrap the expression `(for {something ...})` as `(fl+ (for {something ...}))` the compiler will notice that the internal variables of the loop are used only by `fl-something` functions and avoid creating the secret boxes. (The link by @sorawee has more detailed info.)

> [@lewisl](#):
>
> They seem to violate the idea of using obvious approaches without tricks. But, tricks can be good... Seems like either could be a compiler optimization.

I agree. The fastest code should by the more idiomatic and nicest code. Sometime it's not possible, but it's a good objective. In this case, I think the compiler can be smart enough to make the `fl+` wrapper unnecessary. I didn't wrote the flonum unboxig code, so I'm not sure of the details, but my guess is that it's possible and I made a feature request. (I can try to take look, but not now. Perhaps in a few months.)

---

<div class="post-metadata">

**Author:** ![lewisl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/lewisl/32/1321_2.png) [@lewisl](https://racket.discourse.group/u/lewisl)\
**Post date:** [October 5, 2023, 4:34pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/51 "2023-10-05T16:34:13Z")

</div>

Great, thanks. Does Racket have homogeneous vector types like sbcl?

- Lewis

---

<div class="post-metadata">

**Author:** ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)\
**Post date:** [October 6, 2023, 8:50pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/52 "2023-10-06T20:50:36Z")

</div>

Here's a first step to that: [bench.rkt · GitHub](https://gist.github.com/samth/c20d0421f3504158f5ddae16c6264201)  
It prints the time series of timings, not the histogram of log(frequency) but that should be an easy next step.

Example output:

```scheme
> (bench (repeat vector-sum-for/fold 10 100000 0.5) 50)
███▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂▂
██████████████████████████████████████████████████
>

```

---

<div class="post-metadata">

**Author:** ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)\
**Post date:** [October 7, 2023, 2:09am UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/53 "2023-10-07T02:09:31Z")

</div>

> [@lewisl](#):
>
> Does Racket have homogeneous vector types like sbcl?

Yes. See:

- [5.1&nbsp;Safe Homogenous Vectors](https://docs.racket-lang.org/foreign/homogeneous-vectors.html)
- [SRFI-4](https://docs.racket-lang.org/srfi/srfi-4.html)
- [SRFI-160](https://docs.racket-lang.org/extra-srfi-libs/index.html#%28part._.S.R.F.I-160_.Homogenous_numeric_vector_libraries%29) (Part of my `extra-srfi-libs` package)

---

<div class="post-metadata">

**Author:** ![lewisl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/lewisl/32/1321_2.png) [@lewisl](https://racket.discourse.group/u/lewisl)\
**Post date:** [October 7, 2023, 5:02pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/54 "2023-10-07T17:02:42Z")

</div>

Once again, these functions are crippled by the lack of function overloading. This should be TOPS for making Racket a truly modern, functional language.

We don't have in-fl64vector. And we would need about 12 or so new functions to cover all the types of ffi based vectors.

This problem crops up a lot in the entire Scheme family. It's partly the lack of function overloading and it's partly the lack of container polymorphism: functions on containers that don't depend on element types. This exists in spades for lists, but not for other container types (OK, maybe hash maps, which I haven't played with very much...).

And so we can't write performant code using c-style vectors. Trying to find the source of in-flvector to write a version for f64vector. Where would I find it?

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [October 7, 2023, 10:12pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/55 "2023-10-07T22:12:18Z")

</div>

> [@lewisl](#):
>
> in-flvector

Look in `flonum.rkt` and `private/vector-wraps.rkt`.

[https://github.com/search?q=repo%3Aracket%2Fracket%20define-vector-wraps&type=code](https://github.com/search?q=repo%3Aracket%2Fracket%20define-vector-wraps&type=code)

---

<div class="post-metadata">

**Author:** ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)\
**Post date:** [October 7, 2023, 11:19pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/56 "2023-10-07T23:19:02Z")

</div>

> [@lewisl](#):
>
> We don't have in-f64vector.

I just added `in-@vector` functions to my SRFI-160 port.

(What I miss is not having support for these number types and their vectors baked into Typed Racket. And no longer having 32-bit floats; Racket lost those with the switch to Chez)

---

<div class="post-metadata">

**Author:** ![lewisl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/lewisl/32/1321_2.png) [@lewisl](https://racket.discourse.group/u/lewisl)\
**Post date:** [October 9, 2023, 8:21pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/57 "2023-10-09T20:21:56Z")

</div>

@soegaard I can't make hide nor hair out of any of that code. Some of the files just contains (provides ...) to export functions. Then there must be dozens of calls to define-syntax-rule, which probably creates some global functions that are used elsewhere in the complex module. I can't find an actual definition of a function that begins with in-vector or in-flvector.

There are also calls to define-in-vector-like and make-in-vector-like. But, I have never encountered syntax like this:

```scheme
(define-in-vector-like (in-fXvector* check-fXvector)
       fXvector-str fXvector? fXvector-length :fXvector-gen)

```

What does the preceding do? Is it a call to a function that defines something? What does it define? What is the name of what it defines? Assuming this is actually a call, what the heck does it return? How is the result of the call consumed since it is at top-level.

it is part of the larger definition for define-syntax-rule, which is very cryptic code. it's primary input is the result of a call to define-syntax-wraps, with many input arguments--which probably define some list of function names or functions that will be created on the fly. Since, these are ephemeral it's hard to see what their definitions are. It's all very functional and probably beautiful in Scheme, but seemingly impenetrable.

This whole mess provides only define-vector-wraps. So, this must be called somewhere else where the sought after functions are actually created.

One of the places where this function is used is flonum.rkt. This provides in-flvector, so this is is where in-flvector is presumably defined.

Later in the file is more of the earlier peculiar syntax:

```scheme
(define-vector-wraps "flvector"
  "flonum?" flonum?
  flvector? flvector-length flvector-ref flvector-set! make-flvector
  unsafe-flvector-ref unsafe-flvector-set! unsafe-flvector-length
  in-flvector*
  in-flvector
  for/flvector
  for*/flvector
  flvector-copy
  0.0
  check-flvector)

```

Again, is this a call to define-vector-wraps? Is the rest of the form arguments? Where do they get a value? Is the result a list of the definitions for all of these functions? Seems like that must be true. Where on earth do the values come from? Somewhere else these values/definitions must be supplied.

How does anyone follow so many layers of indirection? There are 28 files in all of the repos of Org Racket that refer to in-flvector. Most are uses of (references to) in-flvector.

One of the files contains a comment that in-flvector is defined in racket/flonum, which is a library--so that only narrows things down a little bit. So, I have to find that library. The repo racket/racket has a variety of directories that seem to contain libraries. Or is there a different repo for Org Racket that has these libraries? Github doesn't make it very easy to navigate very extensive repos.

If I search everywhere in repos of org Racket I get these, below:

Not racket/libs: these are compiled libs for various platforms.  
math-lib/math/flonum.rkt: here we just find a bunch of requires and provides...  
racket/racket/packages: nothing called flonum here...  
racket/racket/src: doesn't look like it's here...  
racket/racket/collects: maybe deeply nested here assuming collects refers to collections

- vector-wraps.rkt is here, but that is just the mysterious code above  
racket/racket/collects/racket/flonum.rkt:

So, pretty much a complete dead end. I am afraid I can't find any way to contribute to in-f64vector. I supposed I don't need to as an flvector is double precision floating point already, just not in c-format, which I don't need since I am not using ffi or any package reliant on ffi.

---

<div class="post-metadata">

**Author:** ![lewisl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/lewisl/32/1321_2.png) [@lewisl](https://racket.discourse.group/u/lewisl)\
**Post date:** [October 9, 2023, 8:31pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/58 "2023-10-09T20:31:13Z")

</div>

@shawnw Where would I find this? I searched all of GitHub and only found srfi-160 for Gauche, chili-scheme, gerbil, saggitarius-scheme and chicken-scheme.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [October 9, 2023, 9:14pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/59 "2023-10-09T21:14:29Z")

</div>

Hi @lewisl

The idea is to share the code that defines `in-vector, in-flvector, ...` as well as `for-fvector, for-flvector, ...`. The macro `define-vector-wraps` simply uses the specialized functions and defines the all the interesting macros at once.

In the case of `f64vector` we can do as follows:

```scheme
#lang racket

(require '#%flfxnum 
         racket/private/vector-wraps
         racket/unsafe/ops
         ffi/vector)

(define unsafe-f64vector-length f64vector-length)

(define-vector-wraps "f64lvector"
  "flonum?" flonum?
  f64vector? f64vector-length f64vector-ref f64vector-set! make-f64vector
  unsafe-f64vector-ref unsafe-f64vector-set! unsafe-f64vector-length
  in-f64vector*
  in-f64vector
  for/f64vector
  for*/f64vector
  f64vector-copy
  0.0
  check-f64vector)

(define v (f64vector 1. 2. 3. 4.))
(for/list ([x (in-f64vector v)]) x)
(for/sum ([x (in-f64vector v)]) x)

```

Note that `unsafe-f64vector-length` seems to be undefined.  
So there is still a side quest, to sqeeze out a little more performance.

---

<div class="post-metadata">

**Author:** ![lewisl](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/lewisl/32/1321_2.png) [@lewisl](https://racket.discourse.group/u/lewisl)\
**Post date:** [October 9, 2023, 9:17pm UTC](https://racket.discourse.group/t/a-micro-benchmark/2347/60 "2023-10-09T21:17:08Z")

</div>

I haven't studied macros yet.

What makes these things macros?

The name place being occupied by a string?

[Previous page](https://racket.discourse.group/t/a-micro-benchmark/2347.md?page=2)

[Next page](https://racket.discourse.group/t/a-micro-benchmark/2347.md?page=4)
