Skip to content

Commit d4918bc

Browse files
committedFeb 28, 2025
More edits on the function-naming draft
1 parent 32d69b9 commit d4918bc

File tree

1 file changed

+36
-1
lines changed

1 file changed

+36
-1
lines changed
 

‎_drafts/2025-02-26-function-naming.md

+36-1
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,41 @@ This has only been a problem for folks running ClojureCLR under Framework 4.x be
273273

274274
## Assembly proliferation and type lookup
275275

276-
Why not get rid of the counter approach and the single eval assembly and go the Clojure(JVM) route by and generate assemblies like popcorn at a movie theater?
276+
Why not get rid of the counter approach and the single eval assembly and go the Clojure(JVM) route by and generate assemblies like popcorn at a movie theater? My disinclination was based on an unexamined hypothesis that that much assembly creation would be a detrimental. But I never tested the hypothesis.
277+
278+
I created a test project to run some numbers. Uninhabited assemblies are actually fairly small -- memory usage per assembly allocation was roughly 850 bytes. (and some might have been garbage -- I was only looking at total bytes generated during the operation). I generated several types in each assembly. They average about 3.5K bytes each.
279+
280+
The price was paid more in type lookup. There is a frequent need to look up a type given a name -- typically from the fully-qualified name, not the assembly-qualified name. For example, looking up a type hint, checking the namespace of a symbol to see if it a type (`Int64/MaxValue`), etc. That lookup involves calls to `Type.GetType()`, looking up generated types, possibly running through all assemblies to ask each if it knows of the type, etc.
281+
The worst case is failure.
282+
283+
I put some counters in `clojure.lang.RT.classForName()` to get some numbers from loading the core Clojure source during startup.
284+
285+
|Lookup type | Count | Description |
286+
|-------------|-------:|:-------------|
287+
| Direct find | 5411 | Call to Type.GetType() succeedeed |
288+
| Duplicate find | 280 | Look up of dynamically generated type in a map |
289+
| Assembly find | 97 | Call to Assembly.GetType(), looping through all assemblies |
290+
| Failure | 193 | None of the above succeeded |
291+
| Total | 5981 | |
292+
293+
In my test project, I did successful and failing lookups (typenames "System.String" and "asdf.asdf" respectively).
294+
I timed lookup via `Type.GetType()` and `Assembly.GetType()` (looping through all assemblies). Here are the resuts:
295+
296+
| Type name | Type.GetType() | Assembly.GetType() |
297+
|-----------|----------------:|-------------------:|
298+
| "System.String" | 91 ms | 84 ms |
299+
| "asdf.asdf" | 77 ms | 241 ms |
300+
301+
Oh, yeah. That's for 100,000 iterations. Now that was for the set of assemblies loaded at startup in the test project -- 11 in total.
302+
I then added 100 dynamic assemblies with 5 classes each. The times for the same lookups were:
303+
304+
| Type name | Type.GetType() | Assembly.GetType() |
305+
|-----------|----------------:|-------------------:|
306+
| "System.String" | 77 ms | 379 ms |
307+
| "asdf.asdf" | 74 ms | 1748 ms |
308+
309+
Clearly, any slowdown due to more assemblies is negligible given the number of failed searches is 1/500 the number of iterations here.
310+
311+
Still, can we do better? Yes. One way would be to create a map from strings to types.
277312

278313

0 commit comments

Comments
 (0)