Skip to content

Part 1. One core · lesson 1 of 42

1. What Komorebi is

Komorebi lets you run your own C++ code on the cores of a Tenstorrent Blackhole card and control it from Python.

A Blackhole card is not a graphics card. It holds 120 small computers, called Tensix cores, on one chip. Each core has its own memory and runs its own program. Nothing spreads your work over them for you: you decide what each core does and when. Komorebi is the small set of tools for that. You write what one core does in C++, and from Python you tell the cores when to do it.

A whole program

Here is a complete program, and what it printed on a card. You do not need to understand it yet: lessons 4 to 8 take it apart, one piece at a time. Read it once and look at what it does.

"""The first look: a core adds two numbers that Python sends it."""

from pathlib import Path

import komorebi as km

HERE = Path(__file__).resolve().parent

program = km.Program("first_look", kernels=HERE / "kernels")

with km.Session() as session:
    run = session.load(program)
    for left, right in [(40, 2), (7, 35), (1000, 2345)]:
        handle = run.submit(0, group=(0, 1), args=[left, right], result=True)
        event = run.wait(handle, timeout=10.0)
        print(f"{left} + {right} = {event.result}")
        assert event.result == left + right
    run.stop()
// The writer kernel: it adds the first two arguments of the command and answers.
#include "komorebi/device/km_worker.hpp"

void kernel_main() {
    km::Writer writer;
    writer.run([&](const km_command_t& command) {
        const uint32_t left = command.a0;
        const uint32_t right = command.a1;
        writer.result(left + right);
        return true;
    });
}
// The reader kernel. It has nothing to do.
#include "komorebi/device/km_worker.hpp"

void kernel_main() {
    km::Reader reader;
    reader.run([&](const km_command_t& command) {});
}
// The compute kernel. It has nothing to do.
#include "komorebi/device/km_worker.hpp"

void kernel_main() {
    km::Compute compute;
    compute.run([&](const km_command_t& command) {});
}

Run python add.py and it prints:

40 + 2 = 42
7 + 35 = 42
1000 + 2345 = 3345

Python sent two numbers to core 0 of the card, three times. The core added them, in C++, on the card, and sent the sum back. Python printed it. The addition did not happen in Python.

What the program does: numbers go to a core of the card, the sum comes back.

Four files for one addition looks like a lot. Two of the C++ files do nothing at all, and lesson 4 says why they have to be there. The tutorial will make each file earn its place.

What this tutorial is

The tutorial has six parts, and every part ends with something you can do:

  1. One core. Run your own code on one core and get an answer back.
  2. Many cores. Run one program on many cores and give each its share of the work.
  3. Data. Move arrays between the card's big memory and the cores, and compute on them.
  4. Cores talking to cores. Send data between cores without going through the big memory.
  5. The other cores. Write C code for the card's other kind of core, and let it drive the first kind.
  6. Practice. Measure, find a bug, read a whole program, and write one of your own.

The list of all lessons is on the left of every page.

How a lesson works

Every lesson teaches one thing. It says what the thing is, then shows its general form with the parts you fill in, then explains each part, and only then shows a complete program that uses it. Under every program is what it printed on a card. The numbers that depend on the machine (a time, for example) are different on yours, and the lesson says so.

A lesson uses only words that an earlier lesson explained. If a word is new, it is explained where it first appears.

Next: lesson 2, Setup and the first run gets your machine ready and runs this program yourself.