Jan 14, 2026

[C++] Cache-friendly

 Just always having int as default if usage is under contract.



Reference:
Object Lifetimes reading minute
alignas(int) unsigned char buffer[sizeof(int)]; // used for provenance contract.

One byte types:

Benchmark shows
char8_t is faster due to optimizer.
this is that a pointer of char, unsigned char, or std::byte type can point to anywhere, thus
data.size() could potentially being modified inside the loop, thus accessing data.size() is necessary.
As for char8_t has no this privilege, thus data.size() is fixed and stored inside a register.




fix: old trick, store the data.size() inside the register ourselves.

or just:


Bitfields is good for saving memory but accessing them are slow (bitmask other values).
also, under meta-programming, type inference of those bitfields type has to be casted.


Reference:

When choosing a container type to use, consider:


L2 cache is used for data and instructions.
i.e. how we code matters the speed, even the results are the same.
e.g.
slower, due to branch and if branch succeed, instructions are replaced in the cache.

faster, due to branch rarely happen, and REPEAT64 has much more instruction than simple count+=d

Summary


Reference:

Always start with DoD; focus on algorithm.

DoD is more packed with data layout, good for caching.

SoA
Reference:
Align with the cache line to avoid false sharing

CS 101, keep false sharing affect in mind.


All-in-all summary


Avoid long branches:

// BAD
void process_data(Data* d) {
    if (!d) {
        // LONG BRANCH / COLD CODE
        // Imagine 100 lines of logging, stack tracing, 
        // and complex error recovery logic here.
        log_error("Null pointer detected...");
        cleanup_subsystems();
        notify_admin_via_snmp();
        throw std::runtime_code("Fatal Error");
    }

    // This "hot" code is now physically far away from the 'if' 
    // check in the compiled binary.
    d->value += 42; 
    d->status = Ready;
}

// Better, avoid I-Cache miss

// Move cold logic to a non-inline function
[[noreturn]] void handle_fatal_error() {
    log_error("Null pointer detected...");
    cleanup_subsystems();
    notify_admin_via_snmp();
    throw std::runtime_code("Fatal Error");
}

void process_data_optimized(Data* d) {
    // C++20 [[likely]]/[[unlikely]] attributes guide the compiler
    if (!d) [[unlikely]] {
        handle_fatal_error(); // A jump to a far-away location happens ONLY on error
    }

    // This code is now physically adjacent to the 'if' check
    d->value += 42; 
    d->status = Ready;
}




No comments:

Post a Comment

Note: Only a member of this blog may post a comment.