Compare commits
4 Commits
9d3a202c27
...
a763bff532
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a763bff532 | ||
|
|
7112937b0b | ||
|
|
a5666328b7 | ||
|
|
5d78cb20df |
39
README.org
39
README.org
@@ -20,8 +20,28 @@ the generator fraction is in green.
|
|||||||
This was done just for fun really, but it's quite fun to see it
|
This was done just for fun really, but it's quite fun to see it
|
||||||
generate a dense number line over many iterations.
|
generate a dense number line over many iterations.
|
||||||
* TODOs
|
* TODOs
|
||||||
** TODO Multithreading
|
** TODO Tree visualisation
|
||||||
SCHEDULED: <2025-11-18 Tue>
|
Instead of a number line, how about visualising the actual tree at
|
||||||
|
work as a graph of nodes? Maybe colouring nodes based on where it is
|
||||||
|
on the number line.
|
||||||
|
** TODO Don't walk the tree everytime we compute_bounds
|
||||||
|
[[file:src/state.cpp::void DrawState::compute_bounds()][location]]
|
||||||
|
|
||||||
|
We already have the latest bound nodes so we're part-way through the
|
||||||
|
tree. Just keep going down what we have so far surely? Even better,
|
||||||
|
don't use nodes _at all_. Run with an index!
|
||||||
|
** DONE Fix weird issue at past 100K nodes
|
||||||
|
std::vector seems to crap itself past 100K nodes - we keep getting
|
||||||
|
heap-use-after-free issues when trying to access the allocator nodes
|
||||||
|
at that point. Seemingly random. What's going on?
|
||||||
|
|
||||||
|
Solution: _everytime_ we want to access the allocator for nontrivial
|
||||||
|
(like memory reads) we need to lock the mutex. No two ways about it.
|
||||||
|
All draw functions were causing the issue.
|
||||||
|
** DONE Prettify code base
|
||||||
|
It's a big blob of code currently in the graphics portion. Not very
|
||||||
|
pretty but it gets the job done. Try modularisation.
|
||||||
|
** DONE Multithreading
|
||||||
Currently single threaded. A multithreaded implementation could have
|
Currently single threaded. A multithreaded implementation could have
|
||||||
multiple nodes generated at once, which would speed up the
|
multiple nodes generated at once, which would speed up the
|
||||||
implementation.
|
implementation.
|
||||||
@@ -29,7 +49,7 @@ implementation.
|
|||||||
Might need to study my current implementation to see if it could be
|
Might need to study my current implementation to see if it could be
|
||||||
done better.
|
done better.
|
||||||
|
|
||||||
*** TODO Formalise state structure (separate drawing functions)
|
*** DONE Formalise state structure (separate drawing functions)
|
||||||
Make a dedicated header and fit the necessary functions to our state
|
Make a dedicated header and fit the necessary functions to our state
|
||||||
structure: [[file:src/main.cpp::struct State][state structure]].
|
structure: [[file:src/main.cpp::struct State][state structure]].
|
||||||
|
|
||||||
@@ -40,14 +60,14 @@ A good working name would be ~cw_state~.
|
|||||||
|
|
||||||
We could then have a separate structure for the drawing context
|
We could then have a separate structure for the drawing context
|
||||||
(~cw_draw~) which can update itself by reading the ~cw_state~.
|
(~cw_draw~) which can update itself by reading the ~cw_state~.
|
||||||
*** TODO Setup a queue and allocator mutex on state
|
*** DONE Setup a queue and allocator mutex on state
|
||||||
We need one for the queue so we can make clean pushes and pops, and
|
We need one for the queue so we can make clean pushes and pops, and
|
||||||
one for the allocator to ensure we're not messing up our indices in
|
one for the allocator to ensure we're not messing up our indices in
|
||||||
the nodes.
|
the nodes.
|
||||||
|
|
||||||
We could just set these up in the state structure itself to make
|
We could just set these up in the state structure itself to make
|
||||||
lookup easier.
|
lookup easier.
|
||||||
*** TODO Make iterate use the state structure and mutexes
|
*** DONE Make iterate use the state structure and mutexes
|
||||||
[[file:src/numerics.cpp::std::tuple<Fraction, Fraction, Fraction>
|
[[file:src/numerics.cpp::std::tuple<Fraction, Fraction, Fraction>
|
||||||
iterate(std::queue<word_t> &queue,]]
|
iterate(std::queue<word_t> &queue,]]
|
||||||
|
|
||||||
@@ -64,11 +84,4 @@ iterate(std::queue<word_t> &queue,]]
|
|||||||
|
|
||||||
I think this scheme minimises the any mutex is locked to just the bare
|
I think this scheme minimises the any mutex is locked to just the bare
|
||||||
minimum, ensuring other threads can get in on the action.
|
minimum, ensuring other threads can get in on the action.
|
||||||
*** TODO Setup a thread pool utilising state and iterate
|
*** DONE Setup a thread pool utilising state and iterate
|
||||||
** TODO Prettify code base
|
|
||||||
It's a big blob of code currently in the graphics portion. Not very
|
|
||||||
pretty but it gets the job done. Try modularisation.
|
|
||||||
** TODO Tree visualisation
|
|
||||||
Instead of a number line, how about visualising the actual tree at
|
|
||||||
work as a graph of nodes? Maybe colouring nodes based on where it is
|
|
||||||
on the number line.
|
|
||||||
|
|||||||
13
build.sh
13
build.sh
@@ -5,12 +5,21 @@ set -xe
|
|||||||
OUT="cw_tree.out"
|
OUT="cw_tree.out"
|
||||||
GFLAGS="-Wall -Wextra -Wswitch-enum -std=c++17"
|
GFLAGS="-Wall -Wextra -Wswitch-enum -std=c++17"
|
||||||
DFLAGS="-ggdb -fsanitize=address -fsanitize=undefined"
|
DFLAGS="-ggdb -fsanitize=address -fsanitize=undefined"
|
||||||
|
RFLAGS="-O2"
|
||||||
CFLAGS="$GFLAGS $DFLAGS"
|
CFLAGS="$GFLAGS $DFLAGS"
|
||||||
LIBS="-lraylib -lm"
|
LIBS="-lraylib -lm"
|
||||||
|
|
||||||
c++ $CFLAGS -o $OUT src/node.cpp src/state.cpp src/worker.cpp src/main.cpp $LIBS
|
build() {
|
||||||
|
c++ $CFLAGS -o $OUT src/node.cpp src/state.cpp src/worker.cpp src/main.cpp $LIBS
|
||||||
|
}
|
||||||
|
|
||||||
if [ "$1" = "run" ]
|
if [ "$1" = "run" ]
|
||||||
then
|
then
|
||||||
./$OUT
|
build && ./$OUT
|
||||||
|
elif [ "$1" = "release" ]
|
||||||
|
then
|
||||||
|
CFLAGS="$GFLAGS $RFLAGS"
|
||||||
|
build;
|
||||||
|
else
|
||||||
|
build;
|
||||||
fi
|
fi
|
||||||
|
|||||||
18
src/main.cpp
18
src/main.cpp
@@ -52,7 +52,7 @@ constexpr u64 clamp_to_width(const DrawState &ds, f64 val)
|
|||||||
(val - ds.bounds.lower_val);
|
(val - ds.bounds.lower_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_tree(const DrawState &ds, const State &state)
|
void draw_tree(DrawState &ds, State &state)
|
||||||
{
|
{
|
||||||
// Number line
|
// Number line
|
||||||
DrawLine(0, HEIGHT / 2, WIDTH, HEIGHT / 2, WHITE);
|
DrawLine(0, HEIGHT / 2, WIDTH, HEIGHT / 2, WHITE);
|
||||||
@@ -63,6 +63,7 @@ void draw_tree(const DrawState &ds, const State &state)
|
|||||||
DrawLine(lower_x, LINE_TOP, lower_x, LINE_BOTTOM, WHITE);
|
DrawLine(lower_x, LINE_TOP, lower_x, LINE_BOTTOM, WHITE);
|
||||||
DrawLine(upper_x, LINE_TOP, upper_x, LINE_BOTTOM, WHITE);
|
DrawLine(upper_x, LINE_TOP, upper_x, LINE_BOTTOM, WHITE);
|
||||||
|
|
||||||
|
state.mutex.lock();
|
||||||
std::stack<std::pair<u64, f64>> stack;
|
std::stack<std::pair<u64, f64>> stack;
|
||||||
cw::node::Node n = state.allocator.get_val(0);
|
cw::node::Node n = state.allocator.get_val(0);
|
||||||
stack.push(std::make_pair(0, n.value.norm));
|
stack.push(std::make_pair(0, n.value.norm));
|
||||||
@@ -87,6 +88,7 @@ void draw_tree(const DrawState &ds, const State &state)
|
|||||||
stack.push(std::make_pair(n.right, right.value.norm));
|
stack.push(std::make_pair(n.right, right.value.norm));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
state.mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
using Clock = std::chrono::steady_clock;
|
using Clock = std::chrono::steady_clock;
|
||||||
@@ -114,13 +116,13 @@ int main(void)
|
|||||||
std::string format_str;
|
std::string format_str;
|
||||||
u64 format_str_width = 0;
|
u64 format_str_width = 0;
|
||||||
|
|
||||||
// Init threads
|
// Init threads
|
||||||
std::thread threads[] = {
|
#define THREADS 15
|
||||||
std::thread(cw::worker::worker, std::ref(state)),
|
std::thread threads[THREADS];
|
||||||
std::thread(cw::worker::worker, std::ref(state)),
|
for (auto i = 0; i < THREADS; ++i)
|
||||||
std::thread(cw::worker::worker, std::ref(state)),
|
{
|
||||||
std::thread(cw::worker::worker, std::ref(state)),
|
threads[i] = std::move(std::thread(cw::worker::worker, std::ref(state)));
|
||||||
};
|
}
|
||||||
|
|
||||||
// Setup raylib window
|
// Setup raylib window
|
||||||
InitWindow(WIDTH, HEIGHT, "Calkin-Wilf tree");
|
InitWindow(WIDTH, HEIGHT, "Calkin-Wilf tree");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace cw::state
|
|||||||
{
|
{
|
||||||
void DrawState::compute_bounds()
|
void DrawState::compute_bounds()
|
||||||
{
|
{
|
||||||
|
state.mutex.lock();
|
||||||
bounds.leftmost = state.allocator.get_val(0);
|
bounds.leftmost = state.allocator.get_val(0);
|
||||||
while (bounds.leftmost.left >= 0)
|
while (bounds.leftmost.left >= 0)
|
||||||
bounds.leftmost = state.allocator.get_val(bounds.leftmost.left);
|
bounds.leftmost = state.allocator.get_val(bounds.leftmost.left);
|
||||||
@@ -19,6 +20,7 @@ namespace cw::state
|
|||||||
bounds.rightmost = state.allocator.get_val(0);
|
bounds.rightmost = state.allocator.get_val(0);
|
||||||
while (bounds.rightmost.right >= 0)
|
while (bounds.rightmost.right >= 0)
|
||||||
bounds.rightmost = state.allocator.get_val(bounds.rightmost.right);
|
bounds.rightmost = state.allocator.get_val(bounds.rightmost.right);
|
||||||
|
state.mutex.unlock();
|
||||||
|
|
||||||
bounds.lower_val = std::floorl(bounds.leftmost.value.norm);
|
bounds.lower_val = std::floorl(bounds.leftmost.value.norm);
|
||||||
bounds.upper_val = std::ceill(bounds.rightmost.value.norm);
|
bounds.upper_val = std::ceill(bounds.rightmost.value.norm);
|
||||||
|
|||||||
@@ -29,14 +29,14 @@ namespace cw::state
|
|||||||
|
|
||||||
struct DrawState
|
struct DrawState
|
||||||
{
|
{
|
||||||
const State &state;
|
State &state;
|
||||||
struct Bounds
|
struct Bounds
|
||||||
{
|
{
|
||||||
cw::node::Node leftmost, rightmost;
|
cw::node::Node leftmost, rightmost;
|
||||||
f64 lower_val, upper_val;
|
f64 lower_val, upper_val;
|
||||||
} bounds;
|
} bounds;
|
||||||
|
|
||||||
DrawState(const State &state) : state{state} {};
|
DrawState(State &state) : state{state} {};
|
||||||
|
|
||||||
void compute_bounds(void);
|
void compute_bounds(void);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user