Last active
April 13, 2023 09:43
-
-
Save FlexW/e6a682af212f6d59d1eff637484e4e12 to your computer and use it in GitHub Desktop.
Clean code bench
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Code from https://blog.codef00.com/2023/04/13/casey-muratori-is-wrong-about-clean-code | |
// I've created this file to try to reproduce the results in this blog. | |
// This little program was timed with Measure-Command { a.exe 9999999 | Out-Default } repeatedly | |
// and compiled with Clang 16.0.0 x86_64-pc_windows-msvc with the command clang++.exe -std=c++17 -O3 cleancodebench.cpp. | |
// On my hardware and operating system Ryzen 7 5800X and Windows 11 I couldn't reproduce the results. | |
// My ranking was: | |
// 1. TestTotalAreaSwitch4 ~15ms | |
// 2. TestTotalAreaSwitch ~550ms | |
// 4. TestTotalAreaVariant ~550ms | |
// 3. TestTotalAreaVariant4 ~590ms | |
#include <stddef.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <variant> | |
using f32 = float; | |
using u32 = uint32_t; | |
constexpr f32 Pi32 = 3.14159; | |
constexpr int Count = 128; | |
class square { | |
public: | |
square(f32 SideInit) : Side(SideInit) {} | |
f32 Area() const { return Side * Side; } | |
private: | |
f32 Side; | |
}; | |
class rectangle { | |
public: | |
rectangle(f32 WidthInit, f32 HeightInit) | |
: Width(WidthInit), Height(HeightInit) {} | |
f32 Area() const { return Width * Height; } | |
private: | |
f32 Width, Height; | |
}; | |
class triangle { | |
public: | |
triangle(f32 BaseInit, f32 HeightInit) : Base(BaseInit), Height(HeightInit) {} | |
f32 Area() const { return 0.5f * Base * Height; } | |
private: | |
f32 Base, Height; | |
}; | |
class circle { | |
public: | |
circle(f32 RadiusInit) : Radius(RadiusInit) {} | |
f32 Area() const { return Pi32 * Radius * Radius; } | |
private: | |
f32 Radius; | |
}; | |
class default_shape { | |
public: | |
f32 Area() const { return 0.0; } | |
}; | |
using any_shape = | |
std::variant<default_shape, square, rectangle, triangle, circle>; | |
f32 TotalAreaVariant(u32 ShapeCount, any_shape *Shapes) { | |
f32 Accum = 0.0f; | |
for (u32 ShapeIndex = 0; ShapeIndex < ShapeCount; ++ShapeIndex) { | |
Accum += std::visit([](auto &&shape) { return shape.Area(); }, | |
Shapes[ShapeIndex]); | |
} | |
return Accum; | |
} | |
f32 TotalAreaVariant4(u32 ShapeCount, any_shape *Shapes) { | |
f32 Accum0 = 0.0f; | |
f32 Accum1 = 0.0f; | |
f32 Accum2 = 0.0f; | |
f32 Accum3 = 0.0f; | |
u32 Count = ShapeCount / 4; | |
while (Count--) { | |
Accum0 += std::visit([](auto &&shape) { return shape.Area(); }, Shapes[0]); | |
Accum1 += std::visit([](auto &&shape) { return shape.Area(); }, Shapes[1]); | |
Accum2 += std::visit([](auto &&shape) { return shape.Area(); }, Shapes[2]); | |
Accum3 += std::visit([](auto &&shape) { return shape.Area(); }, Shapes[3]); | |
Shapes += 4; | |
} | |
f32 Result = (Accum0 + Accum1 + Accum2 + Accum3); | |
return Result; | |
} | |
enum shape_type : u32 { | |
Shape_Square, | |
Shape_Rectangle, | |
Shape_Triangle, | |
Shape_Circle, | |
Shape_Count, | |
}; | |
struct shape_union { | |
shape_type Type; | |
f32 Width; | |
f32 Height; | |
}; | |
f32 GetAreaSwitch(shape_union Shape) { | |
f32 Result = 0.0f; | |
switch (Shape.Type) { | |
case Shape_Square: { | |
Result = Shape.Width * Shape.Width; | |
} break; | |
case Shape_Rectangle: { | |
Result = Shape.Width * Shape.Height; | |
} break; | |
case Shape_Triangle: { | |
Result = 0.5f * Shape.Width * Shape.Height; | |
} break; | |
case Shape_Circle: { | |
Result = Pi32 * Shape.Width * Shape.Width; | |
} break; | |
case Shape_Count: { | |
} break; | |
} | |
return Result; | |
} | |
f32 TotalAreaSwitch(u32 ShapeCount, shape_union *Shapes) { | |
f32 Accum = 0.0f; | |
for (u32 ShapeIndex = 0; ShapeIndex < ShapeCount; ++ShapeIndex) { | |
Accum += GetAreaSwitch(Shapes[ShapeIndex]); | |
} | |
return Accum; | |
} | |
f32 TotalAreaSwitch4(u32 ShapeCount, shape_union *Shapes) { | |
f32 Accum0 = 0.0f; | |
f32 Accum1 = 0.0f; | |
f32 Accum2 = 0.0f; | |
f32 Accum3 = 0.0f; | |
ShapeCount /= 4; | |
while (ShapeCount--) { | |
Accum0 += GetAreaSwitch(Shapes[0]); | |
Accum1 += GetAreaSwitch(Shapes[1]); | |
Accum2 += GetAreaSwitch(Shapes[2]); | |
Accum3 += GetAreaSwitch(Shapes[3]); | |
Shapes += 4; | |
} | |
f32 Result = (Accum0 + Accum1 + Accum2 + Accum3); | |
return Result; | |
} | |
static void TestTotalAreaVariant(u32 TestIterations) { | |
srand(0); // predictable seed | |
any_shape shapes[Count]; | |
for (int i = 0; i < Count; i++) { | |
switch (i & 3) { | |
case 0: | |
shapes[i] = square(rand()); | |
break; | |
case 1: | |
shapes[i] = (rectangle(rand(), rand())); | |
break; | |
case 2: | |
shapes[i] = (triangle(rand(), rand())); | |
break; | |
case 3: | |
shapes[i] = (circle(rand())); | |
break; | |
} | |
} | |
f32 result; | |
for (u32 i = 0; i < TestIterations; ++i) { | |
result += TotalAreaVariant(Count, shapes); | |
} | |
printf("result %f\n", result); | |
} | |
static void TestTotalAreaVariant4(u32 TestIterations) { | |
srand(0); // predictable seed | |
any_shape shapes[Count]; | |
for (int i = 0; i < Count; i++) { | |
switch (i & 3) { | |
case 0: | |
shapes[i] = square(rand()); | |
break; | |
case 1: | |
shapes[i] = (rectangle(rand(), rand())); | |
break; | |
case 2: | |
shapes[i] = (triangle(rand(), rand())); | |
break; | |
case 3: | |
shapes[i] = (circle(rand())); | |
break; | |
} | |
} | |
f32 result; | |
for (u32 i = 0; i < TestIterations; ++i) { | |
result += TotalAreaVariant4(Count, shapes); | |
} | |
printf("result %f\n", result); | |
} | |
static void TestTotalAreaSwitch(u32 TestIterations) { | |
srand(0); // predictable seed | |
shape_union shapes[Count]; | |
for (int i = 0; i < Count; i++) { | |
switch (i & 3) { | |
case 0: | |
shapes[i] = {Shape_Square, static_cast<f32>(rand())}; | |
break; | |
case 1: | |
shapes[i] = {Shape_Rectangle, static_cast<f32>(rand()), | |
static_cast<f32>(rand())}; | |
break; | |
case 2: | |
shapes[i] = {Shape_Triangle, static_cast<f32>(rand()), | |
static_cast<f32>(rand())}; | |
break; | |
case 3: | |
shapes[i] = {Shape_Circle, static_cast<f32>(rand()), | |
static_cast<f32>(rand())}; | |
break; | |
} | |
} | |
f32 result; | |
for (u32 i = 0; i < TestIterations; ++i) { | |
result += TotalAreaSwitch(Count, shapes); | |
} | |
printf("result %f\n", result); | |
} | |
static void TestTotalAreaSwitch4(u32 TestIterations) { | |
srand(0); // predictable seed | |
shape_union shapes[Count]; | |
for (int i = 0; i < Count; i++) { | |
switch (i & 3) { | |
case 0: | |
shapes[i] = {Shape_Square, static_cast<f32>(rand())}; | |
break; | |
case 1: | |
shapes[i] = {Shape_Rectangle, static_cast<f32>(rand()), | |
static_cast<f32>(rand())}; | |
break; | |
case 2: | |
shapes[i] = {Shape_Triangle, static_cast<f32>(rand()), | |
static_cast<f32>(rand())}; | |
break; | |
case 3: | |
shapes[i] = {Shape_Circle, static_cast<f32>(rand()), | |
static_cast<f32>(rand())}; | |
break; | |
} | |
} | |
f32 result; | |
for (u32 i = 0; i < TestIterations; ++i) { | |
result += TotalAreaSwitch4(Count, shapes); | |
} | |
printf("result %f\n", result); | |
} | |
int main(int argc, char **argv) { | |
if (argc != 2) { | |
printf("Usage: %s <iterations>", argv[0]); | |
return 1; | |
} | |
u32 iterations = atoi(argv[1]); | |
// Uncomment one of the test cases | |
// TestTotalAreaVariant(iterations); | |
// TestTotalAreaVariant4(iterations); | |
TestTotalAreaSwitch(iterations); | |
// TestTotalAreaSwitch4(iterations); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment