Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions docs/style_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ typedef enum Value {
* All macros (whether representing constant expressions, sentinels, or function-like macros) must use `SCREAMING_SNAKE_CASE`:
```c
#define INT64_HASH_SET_EMPTY_KEY INT64_MIN
#define GM_CACHE_LINE_PAD(n) ((((n) + (GM_CACHE_LINE_SIZE) - 1) / (GM_CACHE_LINE_SIZE) * (GM_CACHE_LINE_SIZE)) - (n))
#define DECLARE_INT64_STATIC_HASH_SET(name, cap) ...
```

Expand Down Expand Up @@ -282,13 +281,7 @@ static_assert((GM_CACHE_LINE_SIZE & (GM_CACHE_LINE_SIZE - 1)) == 0,
```

### 5.4 Macro Safety
* When defining macros with parameters, enclose all parameter usages and the entire macro expression in parentheses to avoid operator precedence issues:
```c
#define GM_CACHE_LINE_PAD(n) \
((((n) + (GM_CACHE_LINE_SIZE) - 1) / (GM_CACHE_LINE_SIZE) * \
(GM_CACHE_LINE_SIZE)) - \
(n))
```
* When defining macros with parameters, enclose all parameter usages and the entire macro expression in parentheses to avoid operator precedence issues。
* Prefer `static inline` functions over function-like macros whenever feasible.

### 5.5 Array Bounds and Restrict Qualifiers
Expand Down
5 changes: 2 additions & 3 deletions src/core/analysis/analysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#ifndef GAMESMANONE_CORE_ANALYSIS_ANALYSIS_H_
#define GAMESMANONE_CORE_ANALYSIS_ANALYSIS_H_

#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
Expand Down Expand Up @@ -112,9 +113,7 @@ typedef struct Analysis {
* in an array.
*/
typedef struct CacheAlignedAnalysis {
Analysis data; /**< Unpadded data. */
/** Padding CacheAlignedAnalysis to GM_CACHE_LINE_SIZE bytes. */
char padding[GM_CACHE_LINE_PAD(sizeof(Analysis))];
alignas(GM_CACHE_LINE_SIZE) Analysis data; /**< Cache-line-aligned data. */
} CacheAlignedAnalysis;

/**
Expand Down
13 changes: 0 additions & 13 deletions src/core/gamesman_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,6 @@ static_assert(
static_assert((GM_CACHE_LINE_SIZE & (GM_CACHE_LINE_SIZE - 1)) == 0,
"GM_CACHE_LINE_SIZE is not defined as a power of 2");

/**
* @brief Returns the number of bytes to be padded to an object of size `n` so
* that its size becomes a multiple of `GM_CACHE_LINE_SIZE`.
*
* @param[in] n Size of the object in bytes.
*
* @return The number of bytes to be padded.
*/
#define GM_CACHE_LINE_PAD(n) \
((((n) + (GM_CACHE_LINE_SIZE) - 1) / (GM_CACHE_LINE_SIZE) * \
(GM_CACHE_LINE_SIZE)) - \
(n))

// ================================= Allocator =================================

/**
Expand Down
4 changes: 2 additions & 2 deletions src/core/solvers/tier_solver/tier_analyzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "core/solvers/tier_solver/tier_analyzer.h"

#include <assert.h>
#include <stdalign.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stddef.h>
Expand Down Expand Up @@ -84,8 +85,7 @@ static ConcurrentBitset **child_tier_maps;
static int num_threads; // Number of threads available.

typedef struct {
PositionArray a;
char padding[GM_CACHE_LINE_PAD(sizeof(PositionArray))];
alignas(GM_CACHE_LINE_SIZE) PositionArray a;
} PaddedPositionArray;
static PaddedPositionArray *fringe; // Discovered but unprocessed positions.
static PaddedPositionArray *discovered; // Newly discovered positions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#ifndef GAMESMANONE_CORE_SOLVERS_TIER_SOLVER_TIER_WORKER_BACKWARD_INDUCTION_FRONTIER_H_
#define GAMESMANONE_CORE_SOLVERS_TIER_SOLVER_TIER_WORKER_BACKWARD_INDUCTION_FRONTIER_H_

#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>

Expand Down Expand Up @@ -96,9 +97,8 @@ typedef struct FrontierInternal {
* with remoteness i.
*/
typedef struct Frontier {
FrontierInternal f; /**< Unpadded frontier object. */
/** Padding Frontier to GM_CACHE_LINE_SIZE bytes. */
char padding[GM_CACHE_LINE_PAD(sizeof(FrontierInternal))];
/** Cache-line-aligned frontier. */
alignas(GM_CACHE_LINE_SIZE) FrontierInternal f;
} Frontier;

/**
Expand Down
50 changes: 0 additions & 50 deletions tests/unit/core/gamesman_memory_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,56 +36,6 @@ extern "C" const char *__asan_default_options() {
}
#endif

// =================================== Macro ===================================

// Verifies that a size of exactly zero correctly evaluates to needing zero
// bytes of padding.
TEST(CacheLinePadTest, ZeroSize) { EXPECT_EQ(GM_CACHE_LINE_PAD(0), 0); }

// Verifies that sizes that are exact multiples of the cache line size require
// no additional padding.
TEST(CacheLinePadTest, ExactMultiple) {
EXPECT_EQ(GM_CACHE_LINE_PAD(GM_CACHE_LINE_SIZE), 0);
EXPECT_EQ(GM_CACHE_LINE_PAD(GM_CACHE_LINE_SIZE * 2), 0);
EXPECT_EQ(GM_CACHE_LINE_PAD(GM_CACHE_LINE_SIZE * 10), 0);
}

// Verifies that a single byte allocation forces almost an entire cache line of
// padding to reach the next boundary.
TEST(CacheLinePadTest, SmallValue) {
EXPECT_EQ(GM_CACHE_LINE_PAD(1), GM_CACHE_LINE_SIZE - 1);
}

// Verifies the upper boundary condition where the size falls exactly one byte
// short of a full cache line multiple.
TEST(CacheLinePadTest, OneByteUnder) {
EXPECT_EQ(GM_CACHE_LINE_PAD(GM_CACHE_LINE_SIZE - 1), 1);
EXPECT_EQ(GM_CACHE_LINE_PAD((GM_CACHE_LINE_SIZE * 3) - 1), 1);
}

// Verifies the lower boundary condition where the size spills exactly one byte
// over a full cache line multiple.
TEST(CacheLinePadTest, OneByteOver) {
EXPECT_EQ(GM_CACHE_LINE_PAD(GM_CACHE_LINE_SIZE + 1),
GM_CACHE_LINE_SIZE - 1);
EXPECT_EQ(GM_CACHE_LINE_PAD((GM_CACHE_LINE_SIZE * 4) + 1),
GM_CACHE_LINE_SIZE - 1);
}

// Verifies that the macro safely handles larger memory block padding math
// without truncating or evaluating poorly.
TEST(CacheLinePadTest, LargeMemoryBlock) {
// 1MB memory block plus half a cache line offset to verify boundary
// arithmetic at higher scales
const size_t one_mb = 1 << 20;
ASSERT_TRUE(one_mb % GM_CACHE_LINE_SIZE == 0)
<< "GM_CACHE_LINE_SIZE == " << GM_CACHE_LINE_SIZE
<< " does not divide 1 MiB. This is very likely the result of a bug "
"in the cache line size detection program.";
const size_t large_size = one_mb + (GM_CACHE_LINE_SIZE / 2);
EXPECT_EQ(GM_CACHE_LINE_PAD(large_size), GM_CACHE_LINE_SIZE / 2);
}

// ================================= Allocator =================================

// Verifies that populating default options behaves as specified.
Expand Down
Loading