Agent for Optimization: Anthropic's Performance Takehome

Preface

Since graduating from college, I have still been working on optimization, but it has long had little to do with performance optimization. Recently, because I have been doing various kinds of agent-related research, I have seen agents being applied to algorithm design, data generation, kernel writing, and many other areas. After gaining what I consider to be a modest understanding of the latest progress and points of attention across different fields, I currently believe that all kinds of code structures—whether kernels, algorithmic frameworks, or something else—will inevitably be produced fully automatically in the near future, without humans having to write them manually. For a given ISA and a given computational operation, the optimal kernel, assuming we can prove optimality, must be rather “ugly.” It will not have the elegance of a universal algorithm.

One philosophical idea is that “anything that can be well evaluated can eventually be achieved.” This explains, to some extent, the rapid improvement in LLM capabilities after various RL algorithms were applied. Kernels are different from many other domains in that they are exactly a single-objective optimization problem, which makes them a suitable target for a breakthrough.

Problem Description

Through a series of coincidences, I happened to come across Anthropic’s original_performance_takehome. The task is to optimize a kernel, running on a simulated ISA, that performs batched binary-tree traversal plus hashing. The goal is to minimize the number of cycles.

On the GitHub page, its performance is described as follows:

The GitHub repo also says that if you can optimize it below 1487 cycles, you can email Anthropic to get us excited about hiring you. In its copyright file, it says: “Permission is granted to modify and use, but not to publish or redistribute your solutions so it’s hard to find spoilers.”

For a repo this well known, it is impossible that nobody has published their own solution. With some simple searching, one can find solutions posted online claiming 1076 cycles. I did not verify their correctness or whether they involved cheating; I am simply reporting their claimed results here. There are also results such as 1103 and 1149 cycles. If I had not achieved a result better than those published online, there would have been no reason for me to write this blog. That said, I will still respect the repo’s copyright. I will only describe my solution vaguely here and will not publish my code. If you are interested or would like to discuss it with me, feel free to reach out.

My Solution

I used Claude Opus 4.8 with the default Claude Code harness. My approach was to read the solutions written by the agent, explicitly tell the agent how it should modify them, and suggest what kinds of methods it should try.

Version What was done Cycles
0 baseline 147734
1 vectorize + fuse the hash + eliminate the wrap + keep state resident + list scheduler 1864
2 dedupe shallow gathers — compute node_val from the address bits via multilinear interpolation 1693
3 software pipelining; offload the index update to the idle scalar ALU 1412
4 design and adopt a DSL: virtual-register IR → allocate → lower → schedule 1455
5 scheduler picks the engine dynamically + change of state representation 1274
6 load-aware tie-breaking 1258
7 per-group pipeline offsets 1204
8 max out the scratch reuse distance + iterative reordering 1190
9 level 0 of the select tree switched to arithmetic 1171
10 LSB reuse — every tree mask becomes free 1153
11 hoist a constant XOR off the load critical path 1150
12 reclaim dead resident vectors 1147
13 let pause ride an empty slot in an existing bundle 1146
14 hill-climb the per-group pipeline offsets 1135
15 dead-code elimination, per-round direction choice, multilinear trees, bit-reversed trees, ALU-synthesized constants, joint program search over structure × offsets 1035
16 tighten the hash’s temporaries, tighten the dial’s structure 1025
17 revisit the DSL’s design 986

It took me half an hour to reach version 1, about 2 hours in total to reach version 7, about 4 hours in total to reach version 13, and roughly 6 hours to reach the final performance of version 17. I think that, given unlimited time, I could optimize it to around 900 cycles. My guess is that the current best performance is somewhere around 800–900 cycles.

And that is the vague version of my solution. The end.




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • Welcome
  • Rainy Bali
  • Impressions of Java
  • Desert Rose
  • Spreading Eurasia (2)