Compare commits
29
Commits
banana-cakes
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
043178bd25 | ||
|
|
267375cfc9 | ||
|
|
4920af9661 | ||
|
|
501896cba1 | ||
|
|
524354075a | ||
|
|
32d3130b12 | ||
|
|
458f35241d | ||
|
|
bfa70e1eff | ||
|
|
2ef2b5ee35 | ||
|
|
75481a8297 | ||
|
|
d7f060d848 | ||
|
|
f54fdcbfac | ||
|
|
0488aa91c9 | ||
|
|
5550ed849c | ||
|
|
da6c41bbb0 | ||
|
|
668bfc25b9 | ||
|
|
f90183f57c | ||
|
|
1e7df8d578 | ||
|
|
96688c9a00 | ||
|
|
58cb2a8ba2 | ||
|
|
f45aaea181 | ||
|
|
f3d92bc25e | ||
|
|
33bac14926 | ||
|
|
3a8b477563 | ||
|
|
bfeb3aa0c6 | ||
|
|
1a09ed780c | ||
|
|
ae09f3b78e | ||
|
|
b766118a1f | ||
|
|
f53506a723 |
@@ -2,3 +2,4 @@
|
|||||||
*.report
|
*.report
|
||||||
/ftb
|
/ftb
|
||||||
vgcore.*
|
vgcore.*
|
||||||
|
tests/ftb
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "macros.hpp"
|
||||||
|
|
||||||
|
#ifdef USE_FTB_MALLOC
|
||||||
|
namespace Ftb_Malloc_Stats {
|
||||||
|
u32 malloc_calls = 0;
|
||||||
|
u32 free_calls = 0;
|
||||||
|
u32 realloc_calls = 0;
|
||||||
|
u32 calloc_calls = 0;
|
||||||
|
u32 alloca_calls = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ftb_malloc(size) (++Ftb_Malloc_Stats::malloc_calls, malloc(size))
|
||||||
|
#define ftb_free(ptr) (++Ftb_Malloc_Stats::free_calls, free(ptr))
|
||||||
|
#define ftb_realloc(ptr, size) (++Ftb_Malloc_Stats::realloc_calls, realloc(ptr, size))
|
||||||
|
#define ftb_calloc(num, size) (++Ftb_Malloc_Stats::calloc_calls, calloc(num, size))
|
||||||
|
#define ftb_alloca(size) (++Ftb_Malloc_Stats::alloca_calls, alloca(size))
|
||||||
|
|
||||||
|
void print_malloc_stats() {
|
||||||
|
printf("\n"
|
||||||
|
"Global Malloc Stats:\n"
|
||||||
|
"--------------------\n"
|
||||||
|
" ftb_malloc calls: %u\n"
|
||||||
|
" ftb_free calls: %u\n"
|
||||||
|
" ftb_realloc calls: %u\n"
|
||||||
|
" ftb_calloc calls: %u\n"
|
||||||
|
" ftb_alloca calls: %u\n" ,
|
||||||
|
Ftb_Malloc_Stats::malloc_calls,
|
||||||
|
Ftb_Malloc_Stats::free_calls,
|
||||||
|
Ftb_Malloc_Stats::realloc_calls,
|
||||||
|
Ftb_Malloc_Stats::calloc_calls,
|
||||||
|
Ftb_Malloc_Stats::alloca_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define profile_mallocs \
|
||||||
|
MPP_DECLARE(0, u32 MPI_LABEL(profile_mallocs, old_malloc_calls) = Ftb_Malloc_Stats::malloc_calls) \
|
||||||
|
MPP_DECLARE(1, u32 MPI_LABEL(profile_mallocs, old_free_calls) = Ftb_Malloc_Stats::free_calls) \
|
||||||
|
MPP_DECLARE(2, u32 MPI_LABEL(profile_mallocs, old_realloc_calls) = Ftb_Malloc_Stats::realloc_calls) \
|
||||||
|
MPP_DECLARE(3, u32 MPI_LABEL(profile_mallocs, old_calloc_calls) = Ftb_Malloc_Stats::calloc_calls) \
|
||||||
|
MPP_DECLARE(4, u32 MPI_LABEL(profile_mallocs, old_alloca_calls) = Ftb_Malloc_Stats::alloca_calls) \
|
||||||
|
MPP_AFTER(5, { \
|
||||||
|
printf("\n" \
|
||||||
|
"Local Malloc Stats: (%s %s %d)\n" \
|
||||||
|
"-------------------\n" \
|
||||||
|
" ftb_malloc calls: %u\n" \
|
||||||
|
" ftb_free calls: %u\n" \
|
||||||
|
" ftb_realloc calls: %u\n" \
|
||||||
|
" ftb_calloc calls: %u\n" \
|
||||||
|
" ftb_alloca calls: %u\n" , \
|
||||||
|
__func__, __FILE__, __LINE__, \
|
||||||
|
Ftb_Malloc_Stats::malloc_calls - MPI_LABEL(profile_mallocs, old_malloc_calls) , \
|
||||||
|
Ftb_Malloc_Stats::free_calls - MPI_LABEL(profile_mallocs, old_free_calls) , \
|
||||||
|
Ftb_Malloc_Stats::realloc_calls - MPI_LABEL(profile_mallocs, old_realloc_calls) , \
|
||||||
|
Ftb_Malloc_Stats::calloc_calls - MPI_LABEL(profile_mallocs, old_calloc_calls) , \
|
||||||
|
Ftb_Malloc_Stats::alloca_calls - MPI_LABEL(profile_mallocs, old_alloca_calls)); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#else
|
||||||
|
# define ftb_malloc malloc
|
||||||
|
# define ftb_realloc realloc
|
||||||
|
# define ftb_calloc calloc
|
||||||
|
# define ftb_free free
|
||||||
|
# define ftb_alloca alloca
|
||||||
|
#endif
|
||||||
+235
-37
@@ -1,66 +1,190 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
|
# include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
#include "allocation_stats.hpp"
|
||||||
|
#include "macros.hpp"
|
||||||
|
|
||||||
template <typename type>
|
template <typename type>
|
||||||
struct Array_List {
|
struct Stack_Array_List {
|
||||||
type* data;
|
type* data;
|
||||||
u32 length;
|
u32 length;
|
||||||
u32 next_index;
|
u32 count;
|
||||||
|
|
||||||
void alloc(u32 initial_capacity = 16) {
|
Stack_Array_List(u32 length) {
|
||||||
data = (type*)malloc(initial_capacity * sizeof(type));
|
data = (type*)alloca(length);
|
||||||
next_index = 0;
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
length = initial_capacity;
|
if (data == nullptr) {
|
||||||
|
fprintf(stderr, "ERROR: alloca did return nullptr \n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
this->length = length;
|
||||||
|
this->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dealloc() {
|
static Stack_Array_List<type> create_from(std::initializer_list<type> l) {
|
||||||
free(data);
|
Stack_Array_List<type> ret(l.size());
|
||||||
data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (type t : l) {
|
||||||
void clear() {
|
ret.data[ret.count++] = t;
|
||||||
next_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array_List<type> clone() {
|
|
||||||
Array_List<type> ret;
|
|
||||||
ret.length = length;
|
|
||||||
ret.next_index = next_index;
|
|
||||||
|
|
||||||
ret.data = (type*)malloc(length * sizeof(type));
|
|
||||||
for (u32 i = 0; i < next_index; ++i) {
|
|
||||||
ret.data[i] = data[i];
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void extend(std::initializer_list<type> l) {
|
||||||
|
for (type e : l) {
|
||||||
|
append(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
type* begin() {
|
type* begin() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
type* end() {
|
type* end() {
|
||||||
return data+(next_index);
|
return data+(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_index(u32 index) {
|
void remove_index(u32 index) {
|
||||||
data[index] = data[--next_index];
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
|
if (index >= count)
|
||||||
|
fprintf(stderr, "ERROR: removing index that is not in use\n");
|
||||||
|
#endif
|
||||||
|
data[index] = data[--count];
|
||||||
}
|
}
|
||||||
|
|
||||||
void append(type element) {
|
void append(type element) {
|
||||||
if (next_index == length) {
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
length *= 2;
|
if (count == length) {
|
||||||
data = (type*)realloc(data, length * sizeof(type));
|
fprintf(stderr, "ERROR: Stack_Array_List is full!\n");
|
||||||
}
|
}
|
||||||
data[next_index] = element;
|
#endif
|
||||||
next_index++;
|
data[count] = element;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(u32 count) {
|
type& operator[](u32 index) {
|
||||||
if (next_index+count >= (u32)length) {
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename type>
|
||||||
|
struct Array_List {
|
||||||
|
type* data;
|
||||||
|
u32 length;
|
||||||
|
u32 count;
|
||||||
|
|
||||||
|
void alloc(u32 initial_capacity = 16) {
|
||||||
|
data = (type*)ftb_malloc(initial_capacity * sizeof(type));
|
||||||
|
count = 0;
|
||||||
|
length = initial_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Array_List<type> create_from(std::initializer_list<type> l) {
|
||||||
|
Array_List<type> ret;
|
||||||
|
ret.alloc_from(l);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void alloc_from(std::initializer_list<type> l) {
|
||||||
|
length = max(l.size(), 1); // alloc at least one
|
||||||
|
|
||||||
|
data = (type*)ftb_malloc(length * sizeof(type));
|
||||||
|
count = 0;
|
||||||
|
// TODO(Felix): Use memcpy here
|
||||||
|
for (type t : l) {
|
||||||
|
data[count++] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void extend(std::initializer_list<type> l) {
|
||||||
|
reserve(l.size());
|
||||||
|
// TODO(Felix): Use memcpy here
|
||||||
|
for (type e : l) {
|
||||||
|
append(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dealloc() {
|
||||||
|
ftb_free(data);
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains_linear_search(type elem) {
|
||||||
|
for (u32 i = 0; i < count; ++i) {
|
||||||
|
if (data[i] == elem)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains_binary_search(type elem) {
|
||||||
|
return sorted_find(elem) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Array_List<type> clone() {
|
||||||
|
Array_List<type> ret;
|
||||||
|
ret.length = length;
|
||||||
|
ret.count = count;
|
||||||
|
|
||||||
|
ret.data = (type*)ftb_malloc(length * sizeof(type));
|
||||||
|
// TODO(Felix): Maybe use memcpy here
|
||||||
|
for (u32 i = 0; i < count; ++i) {
|
||||||
|
ret.data[i] = data[i];
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_values_from(Array_List<type> other) {
|
||||||
|
// clear the array
|
||||||
|
count = 0;
|
||||||
|
// make sure we have allocated enough
|
||||||
|
reserve(other.count);
|
||||||
|
// copy stuff
|
||||||
|
count = other.count;
|
||||||
|
memcpy(data, other.data, sizeof(type) * other.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
type* begin() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
type* end() {
|
||||||
|
return data+(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_index(u32 index) {
|
||||||
|
data[index] = data[--count];
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(type element) {
|
||||||
|
if (count == length) {
|
||||||
length *= 2;
|
length *= 2;
|
||||||
data = (type*)realloc(data, length * sizeof(type));
|
data = (type*)ftb_realloc(data, length * sizeof(type));
|
||||||
|
}
|
||||||
|
data[count] = element;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(u32 amount) {
|
||||||
|
if (count+amount >= (u32)length) {
|
||||||
|
length *= 2;
|
||||||
|
data = (type*)ftb_realloc(data, length * sizeof(type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +192,7 @@ struct Array_List {
|
|||||||
return data[index];
|
return data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _merge(u32 start, u32 mid, u32 end) {
|
void _merge(u32 start, u32 mid, u32 end) {
|
||||||
u32 start2 = mid + 1;
|
u32 start2 = mid + 1;
|
||||||
|
|
||||||
@@ -102,9 +227,9 @@ struct Array_List {
|
|||||||
|
|
||||||
void sort(s32 left=-1, s32 right=-1) {
|
void sort(s32 left=-1, s32 right=-1) {
|
||||||
if (left == -1) {
|
if (left == -1) {
|
||||||
if (next_index == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
sort(0, next_index - 1);
|
sort(0, count - 1);
|
||||||
return;
|
return;
|
||||||
} else if (left == right) {
|
} else if (left == right) {
|
||||||
return;
|
return;
|
||||||
@@ -118,9 +243,9 @@ struct Array_List {
|
|||||||
_merge(left, middle, right);
|
_merge(left, middle, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sorted_find(type elem, s32 left=-1, s32 right=-1) {
|
s32 sorted_find(type elem, s32 left=-1, s32 right=-1) {
|
||||||
if (left == -1) {
|
if (left == -1) {
|
||||||
return sorted_find(elem, 0, next_index - 1);
|
return sorted_find(elem, 0, count - 1);
|
||||||
} else if (left == right) {
|
} else if (left == right) {
|
||||||
if ((size_t)data[left] == (size_t)elem)
|
if ((size_t)data[left] == (size_t)elem)
|
||||||
return left;
|
return left;
|
||||||
@@ -137,3 +262,76 @@ struct Array_List {
|
|||||||
return middle;
|
return middle;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename type>
|
||||||
|
struct Auto_Array_List : public Array_List<type> {
|
||||||
|
Auto_Array_List(u32 length) {
|
||||||
|
this->alloc(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Auto_Array_List() {
|
||||||
|
this->alloc(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
Auto_Array_List(std::initializer_list<type> l) {
|
||||||
|
this->alloc(l.size());
|
||||||
|
for (type e : l) {
|
||||||
|
this->append(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Auto_Array_List() {
|
||||||
|
ftb_free(this->data);
|
||||||
|
this->data = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename type>
|
||||||
|
struct Queue {
|
||||||
|
Array_List<type> arr_list;
|
||||||
|
u32 next_index;
|
||||||
|
|
||||||
|
void alloc(u32 initial_capacity = 16) {
|
||||||
|
next_index = 0;
|
||||||
|
arr_list.alloc(initial_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dealloc() {
|
||||||
|
arr_list.dealloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(type e) {
|
||||||
|
arr_list.append(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
type get_next() {
|
||||||
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
|
if (next_index >= arr_list.length) {
|
||||||
|
fprintf(stderr, "ERROR: Out of bounds access in queue\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return arr_list.data[next_index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_empty() {
|
||||||
|
return next_index == arr_list.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_count() {
|
||||||
|
return arr_list.count - next_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(type elem) {
|
||||||
|
for (u32 i = next_index; i < arr_list.count; ++i) {
|
||||||
|
if (arr_list[i] == elem)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
next_index = 0;
|
||||||
|
arr_list.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
+39
-15
@@ -1,8 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
#include "arraylist.hpp"
|
#include "arraylist.hpp"
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
|
||||||
template <typename type>
|
template <typename type>
|
||||||
class Bucket_Allocator {
|
struct Bucket_Allocator {
|
||||||
u32 next_index_in_latest_bucket;
|
u32 next_index_in_latest_bucket;
|
||||||
u32 next_bucket_index;
|
u32 next_bucket_index;
|
||||||
u32 bucket_count;
|
u32 bucket_count;
|
||||||
@@ -11,10 +12,14 @@ class Bucket_Allocator {
|
|||||||
Array_List<type*> free_list;
|
Array_List<type*> free_list;
|
||||||
type** buckets;
|
type** buckets;
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
next_index_in_latest_bucket = 0;
|
||||||
|
next_bucket_index = 0;
|
||||||
|
free_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void expand() {
|
void expand() {
|
||||||
// printf("realloc time\n");
|
buckets = (type**)ftb_realloc(buckets, bucket_count * 2 * sizeof(type*));
|
||||||
// realloc time
|
|
||||||
buckets = (type**)realloc(buckets, bucket_count * 2 * sizeof(type*));
|
|
||||||
bucket_count *= 2;
|
bucket_count *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,7 +29,7 @@ class Bucket_Allocator {
|
|||||||
if (next_bucket_index >= bucket_count) {
|
if (next_bucket_index >= bucket_count) {
|
||||||
expand();
|
expand();
|
||||||
}
|
}
|
||||||
buckets[next_bucket_index] = (type*)malloc(bucket_size * sizeof(type));
|
buckets[next_bucket_index] = (type*)ftb_malloc(bucket_size * sizeof(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
void increment_pointers(s32 amount = 1) {
|
void increment_pointers(s32 amount = 1) {
|
||||||
@@ -34,29 +39,48 @@ class Bucket_Allocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
void alloc(u32 bucket_size = 16, u32 initial_bucket_count = 8) {
|
||||||
void alloc(u32 bucket_size, u32 initial_bucket_count) {
|
|
||||||
this->free_list.alloc();
|
this->free_list.alloc();
|
||||||
this->bucket_size = bucket_size;
|
this->bucket_size = bucket_size;
|
||||||
next_index_in_latest_bucket = 0;
|
next_index_in_latest_bucket = 0;
|
||||||
next_bucket_index = 0;
|
next_bucket_index = 0;
|
||||||
bucket_count = initial_bucket_count;
|
bucket_count = initial_bucket_count;
|
||||||
|
|
||||||
buckets = (type**)malloc(bucket_count * sizeof(type*));
|
buckets = (type**)ftb_malloc(bucket_count * sizeof(type*));
|
||||||
buckets[0] = (type*)malloc(bucket_size * sizeof(type));
|
buckets[0] = (type*)ftb_malloc(bucket_size * sizeof(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
void dealloc() {
|
void dealloc() {
|
||||||
for (u32 i = 0; i <= next_bucket_index; ++i) {
|
for (u32 i = 0; i <= next_bucket_index; ++i) {
|
||||||
free(buckets[i]);
|
ftb_free(buckets[i]);
|
||||||
}
|
}
|
||||||
this->free_list.dealloc();
|
this->free_list.dealloc();
|
||||||
free(buckets);
|
ftb_free(buckets);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename proc>
|
u32 count_elements() {
|
||||||
void for_each(proc p) {
|
|
||||||
free_list.sort();
|
free_list.sort();
|
||||||
|
type* val;
|
||||||
|
u32 count = 0;
|
||||||
|
for (u32 i = 0; i < next_bucket_index; ++i) {
|
||||||
|
for (u32 j = 0; j < bucket_size; ++j) {
|
||||||
|
val = buckets[i]+j;
|
||||||
|
if (free_list.sorted_find(val) == -1)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (u32 j = 0; j < next_index_in_latest_bucket; ++j) {
|
||||||
|
val = buckets[next_bucket_index]+j;
|
||||||
|
if (free_list.sorted_find(val) == -1)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename lambda>
|
||||||
|
void for_each(lambda p) {
|
||||||
|
free_list.sort();
|
||||||
|
|
||||||
type* val;
|
type* val;
|
||||||
for (u32 i = 0; i < next_bucket_index; ++i) {
|
for (u32 i = 0; i < next_bucket_index; ++i) {
|
||||||
for (u32 j = 0; j < bucket_size; ++j) {
|
for (u32 j = 0; j < bucket_size; ++j) {
|
||||||
@@ -76,8 +100,8 @@ public:
|
|||||||
type* ret;
|
type* ret;
|
||||||
if (amount == 0) return nullptr;
|
if (amount == 0) return nullptr;
|
||||||
if (amount == 1) {
|
if (amount == 1) {
|
||||||
if (free_list.next_index != 0) {
|
if (free_list.count != 0) {
|
||||||
return free_list.data[--free_list.next_index];
|
return free_list.data[--free_list.count];
|
||||||
}
|
}
|
||||||
ret = buckets[next_bucket_index]+next_index_in_latest_bucket;
|
ret = buckets[next_bucket_index]+next_index_in_latest_bucket;
|
||||||
increment_pointers(1);
|
increment_pointers(1);
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
@echo off
|
|
||||||
|
|
||||||
mkdir bin
|
|
||||||
|
|
||||||
set EXE_RAW=test
|
|
||||||
set BINDIR_RAW=bin
|
|
||||||
set SRC=test.cpp
|
|
||||||
|
|
||||||
set EXE_WIN=%EXE_RAW%.exe
|
|
||||||
set EXE_LINUX=%EXE_RAW%
|
|
||||||
set BINDIR_WIN=.\%BINDIR_RAW%
|
|
||||||
set BINDIR_LINUX=./%BINDIR_RAW%
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo clang:
|
|
||||||
clang -std=c++17 %SRC% -o %BINDIR_WIN%\clang_%EXE_WIN%
|
|
||||||
%BINDIR_WIN%\clang_%EXE_WIN%
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo g++:
|
|
||||||
g++ -std=c++17 %SRC% -o %BINDIR_WIN%\g++_%EXE_WIN%
|
|
||||||
%BINDIR_WIN%\g++_%EXE_WIN%
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo cl:
|
|
||||||
cl %SRC% /nologo /Zi /Fd: %BINDIR_WIN%\cl_%EXE_WIN%.pdb /Fo: %BINDIR_WIN%\ /Fe: %BINDIR_WIN%\cl_%EXE_WIN% /wd4090
|
|
||||||
%BINDIR_WIN%\cl_%EXE_WIN%
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo bash_clang:
|
|
||||||
bash -c "clang -std=c++17 %SRC% -o %BINDIR_LINUX%/bash_clang_%EXE_LINUX% && %BINDIR_LINUX%/bash_clang_%EXE_LINUX%"
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo bash_g++:
|
|
||||||
bash -c "g++ -std=c++17 %SRC% -o %BINDIR_LINUX%/bash_g++_%EXE_LINUX% && %BINDIR_LINUX%/bash_g++_%EXE_LINUX%"
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
TIMEFORMAT=%3lR
|
|
||||||
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
|
||||||
pushd $SCRIPTPATH > /dev/null
|
|
||||||
|
|
||||||
# _DEBUG
|
|
||||||
# time g++ -fpermissive src/main.cpp -g -o ./bin/slime --std=c++17 || exit 1
|
|
||||||
time clang++ -D_DEBUG -D_PROFILING -fpermissive test.cpp -g -o ./ftb --std=c++17 || exit 1
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
time valgrind --leak-check=full ./ftb
|
|
||||||
|
|
||||||
popd > /dev/null
|
|
||||||
unset TIMEFORMAT
|
|
||||||
+362
@@ -0,0 +1,362 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef MSVC
|
||||||
|
#include <immintrin.h>
|
||||||
|
#define platform_independent_cpuid(function_id, array_of_registers) \
|
||||||
|
__cpuid(array_of_registers, function_id)
|
||||||
|
|
||||||
|
#define platform_independent_cpuidex(function_id, sub_function_id, array_of_registers) \
|
||||||
|
__cpuid_count(array_of_registers, function_id, sub_function_id)
|
||||||
|
#else
|
||||||
|
#include <cpuid.h>
|
||||||
|
#define platform_independent_cpuid(function_id, array_of_registers) \
|
||||||
|
__cpuid(function_id, array_of_registers[0], array_of_registers[1], \
|
||||||
|
array_of_registers[2],array_of_registers[3])
|
||||||
|
|
||||||
|
#define platform_independent_cpuidex(function_id, sub_function_id, array_of_registers) \
|
||||||
|
__cpuid_count (function_id, sub_function_id, array_of_registers[0], \
|
||||||
|
array_of_registers[1], array_of_registers[2], \
|
||||||
|
array_of_registers[3])
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum struct Edx_1_Feature_Flags {
|
||||||
|
fpu = 1<<0, // Onboard x87 FPU
|
||||||
|
vme = 1<<1, // Virtual 8086 mode extensions (such as VIF, VIP, PIV)
|
||||||
|
de = 1<<2, // Debugging extensions (CR4 bit 3)
|
||||||
|
pse = 1<<3, // Page Size Extension
|
||||||
|
tsc = 1<<4, // Time Stamp Counter
|
||||||
|
msr = 1<<5, // Model-specific registers
|
||||||
|
pae = 1<<6, // Physical Address Extension
|
||||||
|
mce = 1<<7, // Machine Check Exception
|
||||||
|
cx8 = 1<<8, // CMPXCHG8 (compare-and-swap) instruction
|
||||||
|
apic = 1<<9, // Onboard Advanced Programmable Interrupt Controller
|
||||||
|
_resv1 = 1<<10, // (reserved)
|
||||||
|
sep = 1<<11, // SYSENTER and SYSEXIT instructions
|
||||||
|
mtrr = 1<<12, // Memory Type Range Registers
|
||||||
|
pge = 1<<13, // Page Global Enable bit in CR4
|
||||||
|
mca = 1<<14, // Machine check architecture
|
||||||
|
cmov = 1<<15, // Conditional move and FCMOV instructions
|
||||||
|
pat = 1<<16, // Page Attribute Table
|
||||||
|
pse_36 = 1<<17, // 36-bit page size extension
|
||||||
|
psn = 1<<18, // Processor Serial Number
|
||||||
|
clfsh = 1<<19, // CLFLUSH instruction (SSE2)
|
||||||
|
_resv2 = 1<<20, // (reserved)
|
||||||
|
ds = 1<<21, // Debug store: save trace of executed jumps
|
||||||
|
acpi = 1<<22, // Onboard thermal control MSRs for ACPI
|
||||||
|
mmx = 1<<23, // MMX instructions
|
||||||
|
fxsr = 1<<24, // FXSAVE, FXRESTOR instructions, CR4 bit 9
|
||||||
|
sse = 1<<25, // SSE instructions (a.k.a. Katmai New Instructions)
|
||||||
|
sse2 = 1<<26, // SSE2 instructions
|
||||||
|
ss = 1<<27, // CPU cache implements self-snoop
|
||||||
|
htt = 1<<28, // Hyper-threading
|
||||||
|
tm = 1<<29, // Thermal monitor automatically limits temperature
|
||||||
|
ia64 = 1<<30, // IA64 processor emulating x86
|
||||||
|
pbe = 1<<31, // Pending Break Enable (PBE# pin) wakeup capability
|
||||||
|
};
|
||||||
|
|
||||||
|
enum struct Ecx_1_Feature_Flags {
|
||||||
|
sse3 = 1<<0, // Prescott New Instructions-SSE3 (PNI)
|
||||||
|
pclmulqdq = 1<<1, // PCLMULQDQ
|
||||||
|
dtes64 = 1<<2, // 64-bit debug store (edx bit 21)
|
||||||
|
monitor = 1<<3, // MONITOR and MWAIT instructions (SSE3)
|
||||||
|
ds_cpl = 1<<4, // CPL qualified debug store
|
||||||
|
vmx = 1<<5, // Virtual Machine eXtensions
|
||||||
|
smx = 1<<6, // Safer Mode Extensions (LaGrande)
|
||||||
|
est = 1<<7, // Enhanced SpeedStep
|
||||||
|
tm2 = 1<<8, // Thermal Monitor 2
|
||||||
|
ssse3 = 1<<9, // Supplemental SSE3 instructions
|
||||||
|
cnxt_id = 1<<10, // L1 Context ID
|
||||||
|
sdbg = 1<<11, // Silicon Debug interface
|
||||||
|
fma = 1<<12, // Fused multiply-add (FMA3)
|
||||||
|
cx16 = 1<<13, // CMPXCHG16B instruction
|
||||||
|
xtpr = 1<<14, // Can disable sending task priority messages
|
||||||
|
pdcm = 1<<15, // Perfmon & debug capability
|
||||||
|
_resv1 = 1<<16, // (reserved)
|
||||||
|
pcid = 1<<17, // Process context identifiers (CR4 bit 17)
|
||||||
|
dca = 1<<18, // Direct cache access for DMA writes
|
||||||
|
sse4_1 = 1<<19, // SSE4.1 instructions
|
||||||
|
sse4_2 = 1<<20, // SSE4.2 instructions
|
||||||
|
x2apic = 1<<21, // x2APIC
|
||||||
|
movbe = 1<<22, // MOVBE instruction (big-endian)
|
||||||
|
popcnt = 1<<23, // POPCNT instruction
|
||||||
|
tsc_deadline = 1<<24, // APIC implements one-shot operation using a TSC deadline value
|
||||||
|
aes = 1<<25, // AES instruction set
|
||||||
|
xsave = 1<<26, // XSAVE, XRESTOR, XSETBV, XGETBV
|
||||||
|
osxsave = 1<<27, // XSAVE enabled by OS
|
||||||
|
avx = 1<<28, // Advanced Vector Extensions
|
||||||
|
f16c = 1<<29, // F16C (half-precision) FP feature
|
||||||
|
rdrnd = 1<<30, // RDRAND (on-chip random number generator) feature
|
||||||
|
hypervisor = 1<<31, // Hypervisor present (always zero on physical CPUs)
|
||||||
|
};
|
||||||
|
|
||||||
|
enum struct Ebx_7_Extended_Feature_Flags {
|
||||||
|
fsgsbase = 1<<0, // Access to base of %fs and %gs
|
||||||
|
_idk1 = 1<<1, //
|
||||||
|
sgx = 1<<2, // Software Guard Extensions
|
||||||
|
bmi1 = 1<<3, // Bit Manipulation Instruction Set 1
|
||||||
|
hle = 1<<4, // TSX Hardware Lock Elision
|
||||||
|
avx2 = 1<<5, // Advanced Vector Extensions 2
|
||||||
|
_idk2 = 1<<6, //
|
||||||
|
smep = 1<<7, // Supervisor Mode Execution Prevention
|
||||||
|
bmi2 = 1<<8, // Bit Manipulation Instruction Set 2
|
||||||
|
erms = 1<<9, // Enhanced REP MOVSB/STOSB
|
||||||
|
invpcid = 1<<10, // INVPCID instruction
|
||||||
|
rtm = 1<<11, // TSX Restricted Transactional Memory
|
||||||
|
pqm = 1<<12, // Platform Quality of Service Monitoring
|
||||||
|
_idk3 = 1<<13, //
|
||||||
|
mpx = 1<<14, // Intel MPX (Memory Protection Extensions)
|
||||||
|
pqe = 1<<15, // Platform Quality of Service Enforcement
|
||||||
|
avx512_f = 1<<16, // AVX-512 Foundation
|
||||||
|
avx512_dq = 1<<17, // AVX-512 Doubleword and Quadword Instructions
|
||||||
|
rdseed = 1<<18, // RDSEED instruction
|
||||||
|
adx = 1<<19, // Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
|
||||||
|
smap = 1<<20, // Supervisor Mode Access Prevention
|
||||||
|
avx512_ifma = 1<<21, // AVX-512 Integer Fused Multiply-Add Instructions
|
||||||
|
pcommit = 1<<22, // PCOMMIT instruction
|
||||||
|
clflushopt = 1<<23, // CLFLUSHOPT instruction
|
||||||
|
clwb = 1<<24, // CLWB instruction
|
||||||
|
intel_pt = 1<<25, // Intel Processor Trace
|
||||||
|
avx512_pf = 1<<26, // AVX-512 Prefetch Instructions
|
||||||
|
avx512_er = 1<<27, // AVX-512 Exponential and Reciprocal Instructions
|
||||||
|
avx512_cd = 1<<28, // AVX-512 Conflict Detection Instructions
|
||||||
|
sha = 1<<29, // Intel SHA extensions
|
||||||
|
avx512_bw = 1<<30, // AVX-512 Byte and Word Instructions
|
||||||
|
avx512_vl = 1<<31, // AVX-512 Vector Length Extensions
|
||||||
|
};
|
||||||
|
|
||||||
|
enum struct Ecx_7_Extended_Feature_Flags {
|
||||||
|
prefetchwt1 = 1<<0, // PREFETCHWT1 instruction
|
||||||
|
avx512_vbmi = 1<<1, // AVX-512 Vector Bit Manipulation Instructions
|
||||||
|
umip = 1<<2, // User-mode Instruction Prevention
|
||||||
|
pku = 1<<3, // Memory Protection Keys for User-mode pages
|
||||||
|
ospke = 1<<4, // PKU enabled by OS
|
||||||
|
waitpkg = 1<<5, // Timed pause and user-level monitor/wait
|
||||||
|
avx512_vbmi2 = 1<<6, // AVX-512 Vector Bit Manipulation Instructions 2
|
||||||
|
cet_ss = 1<<7, // Control flow enforcement (CET) shadow stack
|
||||||
|
gfni = 1<<8, // Galois Field instructions
|
||||||
|
vaes = 1<<9, // Vector AES instruction set (VEX-256/EVEX)
|
||||||
|
vpclmulqdq = 1<<10, // CLMUL instruction set (VEX-256/EVEX)
|
||||||
|
avx512_vnni = 1<<11, // AVX-512 Vector Neural Network Instructions
|
||||||
|
avx512_bitalg = 1<<12, // AVX-512 BITALG instructions
|
||||||
|
_resv1 = 1<<13, // (reserved)
|
||||||
|
avx512_vpopcntdq = 1<<14, // AVX-512 Vector Population Count Double and Quad-word
|
||||||
|
_resv2 = 1<<15, // (reserved)
|
||||||
|
intel_5lp = 1<<16, // 5-level paging
|
||||||
|
mawau1 = 1<<17, // The value of userspace MPX Address-Width Adjust used ...
|
||||||
|
mawau2 = 1<<18, // ... by the BNDLDX and BNDSTX Intel MPX instructions ...
|
||||||
|
mawau3 = 1<<19, // ... in 64-bit mode
|
||||||
|
mawau4 = 1<<20, //
|
||||||
|
mawau5 = 1<<21, //
|
||||||
|
rdpid = 1<<22, // Read Processor ID and IA32_TSC_AUX
|
||||||
|
_resv3 = 1<<23, // (reserved)
|
||||||
|
_resv4 = 1<<24, // (reserved)
|
||||||
|
cldemote = 1<<25, // Cache line demote
|
||||||
|
_resv5 = 1<<26, // (reserved)
|
||||||
|
movdiri = 1<<27, //
|
||||||
|
movdir64b = 1<<28, //
|
||||||
|
enqcmd = 1<<29, // Enqueue Stores
|
||||||
|
sgx_lc = 1<<30, // SGX Launch Configuration
|
||||||
|
pks = 1<<31, // Protection keys for supervisor-mode pages
|
||||||
|
};
|
||||||
|
|
||||||
|
enum struct Edx_7_Extended_Feature_Flags {
|
||||||
|
_resv1 = 1<<0, // (reserved)
|
||||||
|
_resv2 = 1<<1, // (reserved)
|
||||||
|
avx512_4vnniw = 1<<2, // AVX-512 4-register Neural Network Instructions
|
||||||
|
avx512_4fmaps = 1<<3, // AVX-512 4-register Multiply Accumulation Single precision
|
||||||
|
fsrm = 1<<4, // Fast Short REP MOVSB
|
||||||
|
_resv3 = 1<<5, // (reserved)
|
||||||
|
_resv4 = 1<<6, // (reserved)
|
||||||
|
_resv5 = 1<<7, // (reserved)
|
||||||
|
avx512_vp2intersect = 1<<8, // AVX-512 VP2INTERSECT Doubleword and Quadword Instructions
|
||||||
|
SRBDS_CTRL = 1<<9, // Special Register Buffer Data Sampling Mitigations
|
||||||
|
md_clear = 1<<10, // VERW instruction clears CPU buffers
|
||||||
|
_resv6 = 1<<11, // (reserved)
|
||||||
|
_resv7 = 1<<12, // (reserved)
|
||||||
|
tsx_force_abort = 1<<13, //
|
||||||
|
serialize = 1<<14, // Serialize instruction execution
|
||||||
|
hybrid = 1<<15, //
|
||||||
|
TSXLDTRK = 1<<16, // TSX suspend load address tracking
|
||||||
|
_resv8 = 1<<17, // (reserved)
|
||||||
|
pconfig = 1<<18, // Platform configuration (Memory Encryption Technologies Instructions)
|
||||||
|
lbr = 1<<19, // Architectural Last Branch Records
|
||||||
|
cet_ibt = 1<<20, // Control flow enforcement (CET) indirect branch tracking
|
||||||
|
_resv9 = 1<<21, // (reserved)
|
||||||
|
amx_bf16 = 1<<22, // Tile computation on bfloat16 numbers
|
||||||
|
_resv10 = 1<<23, // (reserved)
|
||||||
|
amx_tile = 1<<24, // Tile architecture
|
||||||
|
amx_int8 = 1<<25, // Tile computation on 8-bit integers
|
||||||
|
spec_ctrl = 1<<26,
|
||||||
|
// Speculation Control, part of Indirect Branch Control (IBC):
|
||||||
|
// Indirect Branch Restricted Speculation (IBRS) and
|
||||||
|
// Indirect Branch Prediction Barrier (IBPB)
|
||||||
|
stibp = 1<<27, // Single Thread Indirect Branch Predictor, part of IBC
|
||||||
|
l1d_flush = 1<<28, // IA32_FLUSH_CMD MSR
|
||||||
|
ia32_arch_capabilities = 1<<29, // Speculative Side Channel Mitigations
|
||||||
|
ia32_core_capabilities = 1<<30, // Support for a MSR listing model-specific core capabilities
|
||||||
|
ssbd = 1<<31, // Speculative Store Bypass Disable, as mitigation for Speculative Store Bypass (IA32_SPEC_CTRL)
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE(Felix): Left out flags are duplicates from Edx_1_Feature_Flags
|
||||||
|
enum struct Edx_81_Extended_Feature_Flags {
|
||||||
|
syscall = 1<<11, // SYSCALL and SYSRET instructions
|
||||||
|
mp = 1<<19, // Multiprocessor Capable
|
||||||
|
nx = 1<<20, // NX (no-execute) bit
|
||||||
|
mmxext = 1<<22, // Extended MMX
|
||||||
|
fxsr_opt = 1<<25, // FXSAVE/FXRSTOR optimizations
|
||||||
|
pdpe1gb = 1<<26, // Gibibyte pages
|
||||||
|
rdtscp = 1<<27, // RDTSCP instruction
|
||||||
|
l1d_flush = 1<<28, // IA32_FLUSH_CMD MSR
|
||||||
|
lm = 1<<29, // Long mode
|
||||||
|
_3dnowext = 1<<30, // Extended 3DNow!
|
||||||
|
_3dnow = 1<<31, // 3DNow!
|
||||||
|
};
|
||||||
|
|
||||||
|
enum struct Ecx_81_Extended_Feature_Flags {
|
||||||
|
lahf_lm = 1<<0, // LAHF/SAHF in long mode
|
||||||
|
cmp_legacy = 1<<1, // Hyperthreading not valid
|
||||||
|
svm = 1<<2, // Secure Virtual Machine
|
||||||
|
extapic = 1<<3, // Extended APIC space
|
||||||
|
cr8_legacy = 1<<4, // CR8 in 32-bit mode
|
||||||
|
abm = 1<<5, // Advanced bit manipulation (lzcnt and popcnt)
|
||||||
|
sse4a = 1<<6, // SSE4a
|
||||||
|
misalignsse = 1<<7, // Misaligned SSE mode
|
||||||
|
_3dnowprefetch= 1<<8, // PREFETCH and PREFETCHW instructions
|
||||||
|
osvw = 1<<9, // OS Visible Workaround
|
||||||
|
ibs = 1<<10, // Instruction Based Sampling
|
||||||
|
xop = 1<<11, // XOP instruction set
|
||||||
|
skinit = 1<<12, // SKINIT/STGI instructions
|
||||||
|
wdt = 1<<13, // Watchdog timer
|
||||||
|
_resv1 = 1<<14, // (reserved)
|
||||||
|
lwp = 1<<15, // Light Weight Profiling
|
||||||
|
fma4 = 1<<16, // 4 operands fused multiply-add
|
||||||
|
tce = 1<<17, // Translation Cache Extension
|
||||||
|
_resv2 = 1<<18, // (reserved)
|
||||||
|
nodeid_msr = 1<<19, // NodeID MSR
|
||||||
|
_resv3 = 1<<20, // (reserved)
|
||||||
|
tbm = 1<<21, // Trailing Bit Manipulation
|
||||||
|
topoext = 1<<22, // opology Extensions
|
||||||
|
perfctr_core = 1<<23, // Core performance counter extensions
|
||||||
|
perfctr_nb = 1<<24, // NB performance counter extensions
|
||||||
|
_resv4 = 1<<25, // (reserved)
|
||||||
|
dbx = 1<<26, // Data breakpoint extensions
|
||||||
|
perftsc = 1<<27, // Performance TSC
|
||||||
|
pcx_l2i = 1<<28, // L2I perf counter extensions
|
||||||
|
_resv5 = 1<<29, // (reserved)
|
||||||
|
_resv6 = 1<<30, // (reserved)
|
||||||
|
_resv7 = 1<<31, // (reserved)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Cpu_Info {
|
||||||
|
char vendor[0x20];
|
||||||
|
char brand[0x40];
|
||||||
|
|
||||||
|
bool is_intel;
|
||||||
|
bool is_amd;
|
||||||
|
|
||||||
|
int f_1_ECX;
|
||||||
|
int f_1_EDX;
|
||||||
|
int f_7_EBX;
|
||||||
|
int f_7_ECX;
|
||||||
|
int f_7_EDX;
|
||||||
|
int f_81_ECX;
|
||||||
|
int f_81_EDX;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto query_cpu_feature(Cpu_Info* info, Edx_1_Feature_Flags flag) -> bool {
|
||||||
|
return info->f_1_EDX & (int)flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto query_cpu_feature(Cpu_Info* info, Ecx_1_Feature_Flags flag) -> bool {
|
||||||
|
return info->f_1_ECX & (int)flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto query_cpu_feature(Cpu_Info* info, Ebx_7_Extended_Feature_Flags flag) -> bool {
|
||||||
|
return info->f_7_EBX & (int)flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto query_cpu_feature(Cpu_Info* info, Ecx_7_Extended_Feature_Flags flag) -> bool {
|
||||||
|
return info->f_7_ECX & (int)flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto query_cpu_feature(Cpu_Info* info, Edx_7_Extended_Feature_Flags flag) -> bool {
|
||||||
|
return info->f_7_EDX & (int)flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto query_cpu_feature(Cpu_Info* info, Edx_81_Extended_Feature_Flags flag) -> bool {
|
||||||
|
return info->f_81_EDX & (int)flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto query_cpu_feature(Cpu_Info* info, Ecx_81_Extended_Feature_Flags flag) -> bool {
|
||||||
|
return info->f_81_ECX & (int)flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get_cpu_info(Cpu_Info* info) -> void {
|
||||||
|
*info = {};
|
||||||
|
|
||||||
|
int nIds_ = 0;
|
||||||
|
int nExIds_ = 0;
|
||||||
|
|
||||||
|
int register_sets[3][4];
|
||||||
|
|
||||||
|
info->is_intel = false;
|
||||||
|
info->is_amd = false;
|
||||||
|
|
||||||
|
// Calling __cpuid with 0x0 as the function_id argument
|
||||||
|
// gets the number of the highest valid function ID.
|
||||||
|
platform_independent_cpuid(0, register_sets[0]);
|
||||||
|
nIds_ = register_sets[0][0];
|
||||||
|
|
||||||
|
// Capture vendor string
|
||||||
|
memset(info->vendor, 0, sizeof(info->vendor));
|
||||||
|
memcpy(info->vendor + 0, register_sets[0]+1, sizeof(int));
|
||||||
|
memcpy(info->vendor + 4, register_sets[0]+3, sizeof(int));
|
||||||
|
memcpy(info->vendor + 8, register_sets[0]+2, sizeof(int));
|
||||||
|
|
||||||
|
if (strcmp(info->vendor, "GenuineIntel") == 0) {
|
||||||
|
info->is_intel = true;
|
||||||
|
} else if (strcmp(info->vendor, "AuthenticAMD") == 0) {
|
||||||
|
info->is_amd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nIds_ >= 1) {
|
||||||
|
platform_independent_cpuidex(1, 0, register_sets[0]);
|
||||||
|
info->f_1_ECX = register_sets[0][2];
|
||||||
|
info->f_1_EDX = register_sets[0][3];
|
||||||
|
|
||||||
|
if (nIds_ >= 7) {
|
||||||
|
platform_independent_cpuidex(7, 0, register_sets[1]);
|
||||||
|
info->f_7_EBX = register_sets[1][1];
|
||||||
|
info->f_7_ECX = register_sets[1][2];
|
||||||
|
info->f_7_EDX = register_sets[1][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calling __cpuid with 0x80000000 as the function_id argument
|
||||||
|
// gets the number of the highest valid extended ID.
|
||||||
|
platform_independent_cpuid(0x80000000, register_sets[2]);
|
||||||
|
nExIds_ = register_sets[2][0];
|
||||||
|
|
||||||
|
memset(info->brand, 0, sizeof(info->brand));
|
||||||
|
|
||||||
|
// load bitset with flags for function 0x80000001
|
||||||
|
if (nExIds_ >= 0x80000001) {
|
||||||
|
platform_independent_cpuidex(0x80000001, 0, register_sets[2]);
|
||||||
|
info->f_81_ECX = register_sets[2][2];
|
||||||
|
info->f_81_EDX = register_sets[2][3];
|
||||||
|
|
||||||
|
// Interpret CPU brand string if reported
|
||||||
|
if (nExIds_ >= 0x80000004) {
|
||||||
|
platform_independent_cpuidex(0x80000002, 0, register_sets[0]);
|
||||||
|
platform_independent_cpuidex(0x80000003, 0, register_sets[1]);
|
||||||
|
platform_independent_cpuidex(0x80000004, 0, register_sets[2]);
|
||||||
|
|
||||||
|
memcpy(info->brand + 0, register_sets[0], sizeof(register_sets[0]));
|
||||||
|
memcpy(info->brand + 16, register_sets[1], sizeof(register_sets[1]));
|
||||||
|
memcpy(info->brand + 32, register_sets[2], sizeof(register_sets[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "stdarg.h"
|
#include "stdarg.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
@@ -14,21 +15,21 @@ struct Error {
|
|||||||
Error* error = nullptr;
|
Error* error = nullptr;
|
||||||
|
|
||||||
auto delete_error() -> void {
|
auto delete_error() -> void {
|
||||||
free(error);
|
ftb_free(error);
|
||||||
error = nullptr;
|
error = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto create_error(const char* c_func_name, const char* c_file_name,
|
auto create_error(const char* c_func_name, const char* c_file_name,
|
||||||
u32 c_file_line, String type, const char* format, ...) -> void {
|
u32 c_file_line, String type, const char* format, ...) -> void {
|
||||||
|
|
||||||
error = new Error;
|
error = (Error*) ftb_malloc(sizeof(Error));
|
||||||
error->type = type;
|
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
error->message.length = print_va_args_to_string(&(error->message.data), format, &args);
|
error->message.length = print_va_args_to_string(&(error->message.data), format, &args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
|
error->type = type;
|
||||||
print("\n%{color<}%{->Str} error:%{>color} %{->Str}\n",
|
print("\n%{color<}%{->Str} error:%{>color} %{->Str}\n",
|
||||||
console_red, &(error->type), &(error->message));
|
console_red, &(error->type), &(error->message));
|
||||||
|
|
||||||
@@ -53,11 +54,14 @@ auto create_error(const char* c_func_name, const char* c_file_name,
|
|||||||
#define create_generic_error(...) \
|
#define create_generic_error(...) \
|
||||||
__create_error("generic", __VA_ARGS__)
|
__create_error("generic", __VA_ARGS__)
|
||||||
|
|
||||||
#define assert(condition, format, ...) \
|
#ifdef assert
|
||||||
|
#undef assert
|
||||||
|
#endif
|
||||||
|
#define assert(condition, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (!(condition)) { \
|
if (!(condition)) { \
|
||||||
char* msg; \
|
char* msg; \
|
||||||
print_to_string(&msg, format, __VA_ARGS__); \
|
print_to_string(&msg, __VA_ARGS__); \
|
||||||
create_assertion_error("Assertion-error: %s\n" \
|
create_assertion_error("Assertion-error: %s\n" \
|
||||||
" condition: %s\n" \
|
" condition: %s\n" \
|
||||||
" in: %s:%d", \
|
" in: %s:%d", \
|
||||||
|
|||||||
+98
-35
@@ -6,6 +6,14 @@
|
|||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
#include "arraylist.hpp"
|
#include "arraylist.hpp"
|
||||||
|
|
||||||
|
u32 hm_hash(const char* str) {
|
||||||
|
u32 value = str[0] << 7;
|
||||||
|
s32 i = 0;
|
||||||
|
while (str[i]) {
|
||||||
|
value = (10000003 * value) ^ str[i++];
|
||||||
|
}
|
||||||
|
return value ^ i;
|
||||||
|
}
|
||||||
|
|
||||||
u32 hm_hash(char* str) {
|
u32 hm_hash(char* str) {
|
||||||
u32 value = str[0] << 7;
|
u32 value = str[0] << 7;
|
||||||
@@ -20,6 +28,10 @@ u32 hm_hash(void* ptr) {
|
|||||||
return ((u64)ptr * 2654435761) % 4294967296;
|
return ((u64)ptr * 2654435761) % 4294967296;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool hm_objects_match(const char* a, const char* b) {
|
||||||
|
return strcmp(a, b) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool hm_objects_match(char* a, char* b) {
|
inline bool hm_objects_match(char* a, char* b) {
|
||||||
return strcmp(a, b) == 0;
|
return strcmp(a, b) == 0;
|
||||||
}
|
}
|
||||||
@@ -28,15 +40,6 @@ inline bool hm_objects_match(void* a, void* b) {
|
|||||||
return a == b;
|
return a == b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define for_hash_map(hm) \
|
|
||||||
if (decltype((hm).data[0].original) key = 0); else \
|
|
||||||
if (decltype((hm).data[0].object) value = 0); else \
|
|
||||||
for(u32 index = 0; index < (hm).current_capacity; ++index) \
|
|
||||||
if (!((!(hm).data[index].deleted) && \
|
|
||||||
(key = (hm).data[index].original) && \
|
|
||||||
(value = (hm).data[index].object))); else
|
|
||||||
|
|
||||||
template <typename key_type, typename value_type>
|
template <typename key_type, typename value_type>
|
||||||
struct Hash_Map {
|
struct Hash_Map {
|
||||||
u32 current_capacity;
|
u32 current_capacity;
|
||||||
@@ -44,31 +47,56 @@ struct Hash_Map {
|
|||||||
struct HM_Cell {
|
struct HM_Cell {
|
||||||
key_type original;
|
key_type original;
|
||||||
u64 hash;
|
u64 hash;
|
||||||
bool deleted;
|
enum struct Occupancy : u8 {
|
||||||
|
Avaliable = 0,
|
||||||
|
Occupied,
|
||||||
|
Deleted
|
||||||
|
} occupancy;
|
||||||
value_type object;
|
value_type object;
|
||||||
}* data;
|
}* data;
|
||||||
|
|
||||||
|
template <typename lambda>
|
||||||
|
void for_each(lambda p) {
|
||||||
|
for(u32 index = 0; index < current_capacity; ++index)
|
||||||
|
if (data[index].occupancy == HM_Cell::Occupancy::Occupied)
|
||||||
|
p(data[index].original, data[index].object, index);
|
||||||
|
}
|
||||||
|
|
||||||
void alloc(u32 initial_capacity = 8) {
|
void alloc(u32 initial_capacity = 8) {
|
||||||
|
// round up to next pow of 2
|
||||||
|
--initial_capacity;
|
||||||
|
initial_capacity |= initial_capacity >> 1;
|
||||||
|
initial_capacity |= initial_capacity >> 2;
|
||||||
|
initial_capacity |= initial_capacity >> 4;
|
||||||
|
initial_capacity |= initial_capacity >> 8;
|
||||||
|
initial_capacity |= initial_capacity >> 16;
|
||||||
|
++initial_capacity;
|
||||||
|
// until here
|
||||||
current_capacity = initial_capacity;
|
current_capacity = initial_capacity;
|
||||||
cell_count = 0;
|
cell_count = 0;
|
||||||
data = (HM_Cell*)calloc(initial_capacity, sizeof(HM_Cell));
|
data = (HM_Cell*)ftb_calloc(initial_capacity, sizeof(HM_Cell));
|
||||||
}
|
}
|
||||||
|
|
||||||
void dealloc() {
|
void dealloc() {
|
||||||
free(data);
|
ftb_free(data);
|
||||||
data = nullptr;
|
data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
cell_count = 0;
|
||||||
|
memset(data, 0, current_capacity * sizeof(HM_Cell));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
s32 get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) {
|
s32 get_index_of_living_cell_if_it_exists(key_type key, u64 hash_val) {
|
||||||
// s32 index = hash_val & (current_capacity - 1);
|
s32 index = hash_val & (current_capacity - 1);
|
||||||
s32 index = hash_val % current_capacity;
|
|
||||||
HM_Cell cell = data[index];
|
HM_Cell cell = data[index];
|
||||||
/* test if cell exists at that index */
|
/* test if there is or was something there */
|
||||||
if (cell.original) {
|
if (cell.occupancy != HM_Cell::Occupancy::Avaliable) {
|
||||||
/* check if strings match */
|
/* check if objects match */
|
||||||
if (hm_objects_match(key, cell.original)) {
|
if (hm_objects_match(key, cell.original)) {
|
||||||
/* we found it, now check it it is deleted: */
|
/* we found it, now check it it is deleted: */
|
||||||
if (cell.deleted) {
|
if (cell.occupancy == HM_Cell::Occupancy::Deleted) {
|
||||||
/* we found it but it was deleted, we */
|
/* we found it but it was deleted, we */
|
||||||
/* dont have to check for collisions then */
|
/* dont have to check for collisions then */
|
||||||
return -1;
|
return -1;
|
||||||
@@ -77,16 +105,21 @@ struct Hash_Map {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* strings dont match, this means we have */
|
/* objects dont match, this means we have */
|
||||||
/* a collision. We just search forward */
|
/* a collision. We just search forward */
|
||||||
for (u32 i = 0; i < current_capacity; ++i) {
|
for (u32 i = 0; i < current_capacity; ++i) {
|
||||||
u32 new_idx = (i + index) % current_capacity;
|
u32 new_idx = (i + index) & (current_capacity - 1);
|
||||||
cell = data[new_idx];
|
cell = data[new_idx];
|
||||||
if (!cell.original)
|
/* If we find a avaliable cell while looking */
|
||||||
|
/* forward, the object is not in the hm */
|
||||||
|
if (cell.occupancy == HM_Cell::Occupancy::Avaliable)
|
||||||
return -1;
|
return -1;
|
||||||
|
/* If the objects don't match, keep looking */
|
||||||
if (!hm_objects_match(key, cell.original))
|
if (!hm_objects_match(key, cell.original))
|
||||||
continue;
|
continue;
|
||||||
if (cell.deleted)
|
/* TODO(Felix): If the objects do match, */
|
||||||
|
/* and it is deleted, we should return -1? */
|
||||||
|
if (cell.occupancy == HM_Cell::Occupancy::Deleted)
|
||||||
continue;
|
continue;
|
||||||
return new_idx;
|
return new_idx;
|
||||||
}
|
}
|
||||||
@@ -108,9 +141,12 @@ struct Hash_Map {
|
|||||||
|
|
||||||
key_type search_key_to_object(value_type v) {
|
key_type search_key_to_object(value_type v) {
|
||||||
for (u32 i = 0; i < current_capacity; ++i) {
|
for (u32 i = 0; i < current_capacity; ++i) {
|
||||||
if (data[i].object == v && !data[i].deleted)
|
if (data[i].object == v &&
|
||||||
|
data[i].occupancy == HM_Cell::Occupancy::Occupied)
|
||||||
|
{
|
||||||
return data[i].original;
|
return data[i].original;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +156,7 @@ struct Hash_Map {
|
|||||||
// QUESTION(Felix): Does it make sense to
|
// QUESTION(Felix): Does it make sense to
|
||||||
// ret.reserve(this->cell_count)?
|
// ret.reserve(this->cell_count)?
|
||||||
for (u32 i = 0; i < current_capacity; ++i) {
|
for (u32 i = 0; i < current_capacity; ++i) {
|
||||||
if (data[i].original && !data[i].deleted)
|
if (data[i].occupancy == HM_Cell::Occupancy::Occupied)
|
||||||
ret.append(data[i].original);
|
ret.append(data[i].original);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -138,19 +174,31 @@ struct Hash_Map {
|
|||||||
return get_object(key, hm_hash((key_type)key));
|
return get_object(key, hm_hash((key_type)key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_type* get_object_ptr(key_type key, u64 hash_val) {
|
||||||
|
s32 index = get_index_of_living_cell_if_it_exists(key, hash_val);
|
||||||
|
if (index != -1) {
|
||||||
|
return &(data[index].object);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type* get_object_ptr(key_type key) {
|
||||||
|
return get_object_ptr(key, hm_hash((key_type)key));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void delete_object(key_type key) {
|
void delete_object(key_type key) {
|
||||||
s32 index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
|
s32 index = get_index_of_living_cell_if_it_exists(key, hm_hash((key_type)key));
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
data[index].deleted = true;
|
data[index].occupancy = HM_Cell::Occupancy::Deleted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_object(key_type key, value_type obj, u64 hash_val) {
|
void set_object(key_type key, value_type obj, u64 hash_val) {
|
||||||
u32 index = hash_val % current_capacity;
|
u32 index = hash_val & (current_capacity - 1);
|
||||||
|
|
||||||
/* if we the desired cell is just empty, write to it and done :) */
|
/* if we the desired cell is avaliable, write to it and done :) */
|
||||||
if (!data[index].original) {
|
if (data[index].occupancy == HM_Cell::Occupancy::Avaliable) {
|
||||||
/* insert new cell into desired slot */
|
/* insert new cell into desired slot */
|
||||||
++cell_count;
|
++cell_count;
|
||||||
} else {
|
} else {
|
||||||
@@ -161,26 +209,26 @@ struct Hash_Map {
|
|||||||
/* collision, check resize */
|
/* collision, check resize */
|
||||||
if ((cell_count*1.0f / current_capacity) > 0.666f) {
|
if ((cell_count*1.0f / current_capacity) > 0.666f) {
|
||||||
auto old_data = data;
|
auto old_data = data;
|
||||||
data = (HM_Cell*)calloc(current_capacity*4, sizeof(HM_Cell));
|
data = (HM_Cell*)ftb_calloc(current_capacity*4, sizeof(HM_Cell));
|
||||||
cell_count = 0;
|
cell_count = 0;
|
||||||
current_capacity *= 4;
|
current_capacity *= 4;
|
||||||
|
|
||||||
/* insert all old items again */
|
/* insert all old items again */
|
||||||
for (u32 i = 0; i < current_capacity/4; ++i) {
|
for (u32 i = 0; i < current_capacity/4; ++i) {
|
||||||
auto cell = old_data[i];
|
auto cell = old_data[i];
|
||||||
if (cell.original) {
|
if (cell.occupancy == HM_Cell::Occupancy::Occupied) {
|
||||||
set_object(cell.original, cell.object, cell.hash);
|
set_object(cell.original, cell.object, cell.hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(old_data);
|
ftb_free(old_data);
|
||||||
index = hash_val % current_capacity;
|
index = hash_val & (current_capacity - 1);
|
||||||
}
|
}
|
||||||
++cell_count;
|
++cell_count;
|
||||||
/* search for empty slot for new cell starting at desired index; */
|
/* search for empty slot for new cell starting at desired index; */
|
||||||
/* preventing gotos using lambdas! */
|
/* preventing gotos using lambdas! */
|
||||||
[&]{
|
[&]{
|
||||||
for (u32 i = index; i < current_capacity; ++i) {
|
for (u32 i = index; i < current_capacity; ++i) {
|
||||||
if (!data[i].original ||
|
if (data[i].occupancy == HM_Cell::Occupancy::Avaliable ||
|
||||||
hm_objects_match(data[i].original, key))
|
hm_objects_match(data[i].original, key))
|
||||||
{
|
{
|
||||||
index = i;
|
index = i;
|
||||||
@@ -188,7 +236,7 @@ struct Hash_Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (u32 i = 0; i < index; ++i) {
|
for (u32 i = 0; i < index; ++i) {
|
||||||
if (!data[i].original ||
|
if (data[i].occupancy == HM_Cell::Occupancy::Avaliable ||
|
||||||
hm_objects_match(data[i].original, key))
|
hm_objects_match(data[i].original, key))
|
||||||
{
|
{
|
||||||
index = i;
|
index = i;
|
||||||
@@ -199,7 +247,7 @@ struct Hash_Map {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data[index].deleted = false;
|
data[index].occupancy = HM_Cell::Occupancy::Occupied;
|
||||||
data[index].original = key;
|
data[index].original = key;
|
||||||
data[index].hash = hash_val;
|
data[index].hash = hash_val;
|
||||||
data[index].object = obj;
|
data[index].object = obj;
|
||||||
@@ -209,4 +257,19 @@ struct Hash_Map {
|
|||||||
u64 hash_val = hm_hash((key_type)key);
|
u64 hash_val = hm_hash((key_type)key);
|
||||||
set_object(key, obj, hash_val);
|
set_object(key, obj, hash_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_occupancy(const char* path) {
|
||||||
|
FILE* out = fopen(path, "w");
|
||||||
|
defer { fclose(out); };
|
||||||
|
for (u32 i = 0; i < current_capacity; ++i) {
|
||||||
|
if (data[i].occupancy == HM_Cell::Occupancy::Avaliable) {
|
||||||
|
fprintf(out, "%04u [FREE]\n", i);
|
||||||
|
} else if (data[i].occupancy == HM_Cell::Occupancy::Deleted) {
|
||||||
|
fprintf(out, "%04u [DELETED] hash: %llu (wants to be %llu)\n", i, data[i].hash, data[i].hash & (current_capacity - 1));
|
||||||
|
} else {
|
||||||
|
fprintf(out, "%04u [OCCUPIED] hash: %llu (wants to be %llu)\n", i, data[i].hash, data[i].hash & (current_capacity - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,36 +49,29 @@ struct Lambda<R(Args...)>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Hook {
|
||||||
struct Hook : Array_List<Lambda<void()>> {
|
Array_List<Lambda<void()>> lambdas;
|
||||||
Hook() {
|
Hook() {
|
||||||
alloc();
|
lambdas.alloc();
|
||||||
}
|
}
|
||||||
~Hook () {
|
~Hook () {
|
||||||
dealloc();
|
lambdas.dealloc();
|
||||||
}
|
}
|
||||||
void operator<<(Lambda<void()> f) {
|
void operator<<(Lambda<void()>&& f) {
|
||||||
// FIXME(Felix): Why can I not call Array_List::append here??? Hallo?
|
lambdas.append(f);
|
||||||
if (next_index == length) {
|
|
||||||
length *= 2;
|
|
||||||
data = (Lambda<void()>*)realloc(data, length * sizeof(Lambda<void()>));
|
|
||||||
}
|
|
||||||
data[next_index] = f;
|
|
||||||
next_index++;
|
|
||||||
}
|
}
|
||||||
void operator()() {
|
void operator()() {
|
||||||
while(next_index --> 0) {
|
for (auto l : lambdas) {
|
||||||
fflush(stdout);
|
l();
|
||||||
data[next_index]();
|
|
||||||
}
|
}
|
||||||
next_index = 0;
|
lambdas.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __System_Shutdown_Hook : Hook {
|
// struct __System_Shutdown_Hook : Hook {
|
||||||
void operator()() = delete;
|
// void operator()() = delete;
|
||||||
~__System_Shutdown_Hook() {
|
// ~__System_Shutdown_Hook() {
|
||||||
Hook::operator()();
|
// Hook::operator()();
|
||||||
dealloc();
|
// lambdas.dealloc();
|
||||||
}
|
// }
|
||||||
} system_shutdown_hook;
|
// } system_shutdown_hook;
|
||||||
|
|||||||
+89
@@ -1,10 +1,60 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "platform.hpp"
|
||||||
|
|
||||||
|
#ifdef FTB_WINDOWS
|
||||||
|
#else
|
||||||
|
# include <signal.h> // for sigtrap
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#define proc auto
|
#define proc auto
|
||||||
#define concat(x, y) x ## y
|
#define concat(x, y) x ## y
|
||||||
#define label(x, y) concat(x, y)
|
#define label(x, y) concat(x, y)
|
||||||
|
|
||||||
|
#define MPI_LABEL(id1,id2) \
|
||||||
|
label(MPI_LABEL_ ## id1 ## _ ## id2 ## _, __LINE__)
|
||||||
|
|
||||||
|
#define MPP_DECLARE(labid, declaration) \
|
||||||
|
if (0) \
|
||||||
|
; \
|
||||||
|
else \
|
||||||
|
for (declaration;;) \
|
||||||
|
if (1) { \
|
||||||
|
goto MPI_LABEL(labid, body); \
|
||||||
|
MPI_LABEL(labid, done): break; \
|
||||||
|
} else \
|
||||||
|
while (1) \
|
||||||
|
if (1) \
|
||||||
|
goto MPI_LABEL(labid, done); \
|
||||||
|
else \
|
||||||
|
MPI_LABEL(labid, body):
|
||||||
|
|
||||||
|
#define MPP_BEFORE(labid,before) \
|
||||||
|
if (1) { \
|
||||||
|
before; \
|
||||||
|
goto MPI_LABEL(labid, body); \
|
||||||
|
} else \
|
||||||
|
MPI_LABEL(labid, body):
|
||||||
|
|
||||||
|
#define MPP_AFTER(labid,after) \
|
||||||
|
if (1) \
|
||||||
|
goto MPI_LABEL(labid, body); \
|
||||||
|
else \
|
||||||
|
while (1) \
|
||||||
|
if (1) { \
|
||||||
|
after; \
|
||||||
|
break; \
|
||||||
|
} else \
|
||||||
|
MPI_LABEL(labid, body):
|
||||||
|
|
||||||
|
|
||||||
|
// #ifndef min
|
||||||
|
#define min(a, b) ((a) < (b)) ? (a) : (b)
|
||||||
|
// #endif
|
||||||
|
// #ifndef max
|
||||||
|
#define max(a, b) ((a) > (b)) ? (a) : (b)
|
||||||
|
// #endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defer *
|
* Defer *
|
||||||
@@ -124,3 +174,42 @@ else
|
|||||||
call2(var);
|
call2(var);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define panic(...) \
|
||||||
|
do { \
|
||||||
|
print("%{color<}[Panic]%{>color} in " \
|
||||||
|
"file %{color<}%{->char}%{>color} " \
|
||||||
|
"line %{color<}%{u32}%{>color}: " \
|
||||||
|
"(%{color<}%{->char}%{>color})\n", \
|
||||||
|
console_red, console_cyan, __FILE__, console_cyan, __LINE__, \
|
||||||
|
console_cyan, __func__); \
|
||||||
|
print("%{color<}", console_red); \
|
||||||
|
print(__VA_ARGS__); \
|
||||||
|
print("%{>color}\n"); \
|
||||||
|
fflush(stdout); \
|
||||||
|
print_stacktrace(); \
|
||||||
|
debug_break(); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#define panic_if(cond, ...) \
|
||||||
|
if(!(cond)); \
|
||||||
|
else panic(__VA_ARGS__)
|
||||||
|
|
||||||
|
#ifdef FTB_DEBUG_LOG
|
||||||
|
# define debug_log(...) \
|
||||||
|
do { \
|
||||||
|
print("%{color<}[INFO " __FILE__ ":%{color<}%{->char}" \
|
||||||
|
"%{>color}]%{>color} ", \
|
||||||
|
console_green, console_cyan, __func__); \
|
||||||
|
println(__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
# define debug_log(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FTB_WINDOWS
|
||||||
|
# define debug_break() __debugbreak()
|
||||||
|
#else
|
||||||
|
# define debug_break() raise(SIGTRAP);
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -6,7 +6,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "platform.hpp"
|
||||||
|
|
||||||
|
#ifdef FTB_WINDOWS
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
#include "hashmap.hpp"
|
#include "hashmap.hpp"
|
||||||
#include "hooks.hpp"
|
#include "hooks.hpp"
|
||||||
|
|
||||||
@@ -61,7 +65,7 @@ int maybe_special_print(FILE* file, static_string format, int* pos, va_list* arg
|
|||||||
if (format[end_pos] == 0)
|
if (format[end_pos] == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
char* spec = (char*)malloc(end_pos - (*pos));
|
char* spec = (char*)ftb_alloca(end_pos - (*pos));
|
||||||
strncpy(spec, format+(*pos)+1, end_pos - (*pos));
|
strncpy(spec, format+(*pos)+1, end_pos - (*pos));
|
||||||
spec[end_pos - (*pos)-1] = '\0';
|
spec[end_pos - (*pos)-1] = '\0';
|
||||||
|
|
||||||
@@ -82,10 +86,9 @@ int maybe_special_print(FILE* file, static_string format, int* pos, va_list* arg
|
|||||||
|
|
||||||
if (type == Printer_Function_Type::unknown) {
|
if (type == Printer_Function_Type::unknown) {
|
||||||
printf("ERROR: %s printer not found\n", spec);
|
printf("ERROR: %s printer not found\n", spec);
|
||||||
free(spec);
|
ftb_free(spec);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
free(spec);
|
|
||||||
|
|
||||||
if (format[end_pos] == ',') {
|
if (format[end_pos] == ',') {
|
||||||
int element_count;
|
int element_count;
|
||||||
@@ -261,7 +264,7 @@ int maybe_fprintf(FILE* file, static_string format, int* pos, va_list* arg_list)
|
|||||||
format[end_pos] == '%')
|
format[end_pos] == '%')
|
||||||
{
|
{
|
||||||
writen_len = end_pos - *pos + 2;
|
writen_len = end_pos - *pos + 2;
|
||||||
char* temp = (char*)malloc((writen_len+1)* sizeof(char));
|
char* temp = (char*)alloca((writen_len+1)* sizeof(char));
|
||||||
temp[0] = '%';
|
temp[0] = '%';
|
||||||
temp[1] = 0;
|
temp[1] = 0;
|
||||||
strncpy(temp+1, format+*pos, writen_len);
|
strncpy(temp+1, format+*pos, writen_len);
|
||||||
@@ -269,15 +272,18 @@ int maybe_fprintf(FILE* file, static_string format, int* pos, va_list* arg_list)
|
|||||||
|
|
||||||
// printf("\ntest:: len(%s) = %d\n", temp, writen_len+1);
|
// printf("\ntest:: len(%s) = %d\n", temp, writen_len+1);
|
||||||
|
|
||||||
writen_len = vfprintf(file, temp, *arg_list);
|
/// NOTE(Felix): Somehow we have to pass a copy of the list to vfprintf
|
||||||
|
// because otherwise it destroys it on some platforms :(
|
||||||
|
va_list arg_list_copy;
|
||||||
|
va_copy(arg_list_copy, *arg_list);
|
||||||
|
writen_len = vfprintf(file, temp, arg_list_copy);
|
||||||
|
va_end(arg_list_copy);
|
||||||
|
|
||||||
// NOTE(Felix): For WSL Linux we have to manually overstep the
|
// NOTE(Felix): maually overstep the args that vfprintf will have used
|
||||||
// used args
|
|
||||||
for (int i = 0; i < used_arg_values; ++i) {
|
for (int i = 0; i < used_arg_values; ++i) {
|
||||||
va_arg(*arg_list, void*);
|
va_arg(*arg_list, void*);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(temp);
|
|
||||||
*pos = end_pos;
|
*pos = end_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,9 +305,9 @@ int print_va_args_to_file(FILE* file, static_string format, va_list* arg_list) {
|
|||||||
int move = maybe_special_print(file, format, &pos, arg_list);
|
int move = maybe_special_print(file, format, &pos, arg_list);
|
||||||
if (move == 0) {
|
if (move == 0) {
|
||||||
move = maybe_fprintf(file, format, &pos, arg_list);
|
move = maybe_fprintf(file, format, &pos, arg_list);
|
||||||
if (move == 0) {
|
if (move == -1) {
|
||||||
putchar('%');
|
fputc('%', file);
|
||||||
putchar(c);
|
fputc(c, file);
|
||||||
move = 1;
|
move = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,7 +326,7 @@ int print_va_args_to_string(char** out, static_string format, va_list* arg_list)
|
|||||||
|
|
||||||
int num_printed_chars = print_va_args_to_file(t_file, format, arg_list);
|
int num_printed_chars = print_va_args_to_file(t_file, format, arg_list);
|
||||||
|
|
||||||
*out = (char*)malloc(sizeof(char) * (num_printed_chars+1));
|
*out = (char*)ftb_malloc(sizeof(char) * (num_printed_chars+1));
|
||||||
|
|
||||||
rewind(t_file);
|
rewind(t_file);
|
||||||
fread(*out, sizeof(char), num_printed_chars, t_file);
|
fread(*out, sizeof(char), num_printed_chars, t_file);
|
||||||
@@ -348,7 +354,7 @@ int print_to_string(char** out, static_string format, ...) {
|
|||||||
va_end(arg_list);
|
va_end(arg_list);
|
||||||
|
|
||||||
|
|
||||||
*out = (char*)malloc(sizeof(char) * (num_printed_chars+1));
|
*out = (char*)ftb_malloc(sizeof(char) * (num_printed_chars+1));
|
||||||
|
|
||||||
rewind(t_file);
|
rewind(t_file);
|
||||||
fread(*out, sizeof(char), num_printed_chars, t_file);
|
fread(*out, sizeof(char), num_printed_chars, t_file);
|
||||||
@@ -381,6 +387,20 @@ int print(static_string format, ...) {
|
|||||||
return num_printed_chars;
|
return num_printed_chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int println(static_string format, ...) {
|
||||||
|
va_list arg_list;
|
||||||
|
va_start(arg_list, format);
|
||||||
|
|
||||||
|
int num_printed_chars = print_va_args_to_file(ftb_stdout, format, &arg_list);
|
||||||
|
num_printed_chars += print("\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
va_end(arg_list);
|
||||||
|
|
||||||
|
return num_printed_chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int print_bool(FILE* f, u32 val) {
|
int print_bool(FILE* f, u32 val) {
|
||||||
return print_to_file(f, val ? "true" : "false");
|
return print_to_file(f, val ? "true" : "false");
|
||||||
}
|
}
|
||||||
@@ -389,6 +409,28 @@ int print_u32(FILE* f, u32 num) {
|
|||||||
return print_to_file(f, "%u", num);
|
return print_to_file(f, "%u", num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int print_spaces(FILE* f, s32 num) {
|
||||||
|
int sum = 0;
|
||||||
|
|
||||||
|
while (num >= 8) {
|
||||||
|
// println("%d", 8);
|
||||||
|
sum += print_to_file(f, " ");
|
||||||
|
num -= 8;
|
||||||
|
}
|
||||||
|
while (num >= 4) {
|
||||||
|
// println("%d", 4);
|
||||||
|
sum += print_to_file(f, " ");
|
||||||
|
num -= 4;
|
||||||
|
}
|
||||||
|
while (num --> 0) {
|
||||||
|
// println("%d", 1);
|
||||||
|
sum += print_to_file(f, " ");
|
||||||
|
num--;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int print_u64(FILE* f, u64 num) {
|
int print_u64(FILE* f, u64 num) {
|
||||||
return print_to_file(f, "%llu", num);
|
return print_to_file(f, "%llu", num);
|
||||||
}
|
}
|
||||||
@@ -415,11 +457,11 @@ int print_color_start(FILE* f, char* str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int print_color_end(FILE* f) {
|
int print_color_end(FILE* f) {
|
||||||
--color_stack.next_index;
|
--color_stack.count;
|
||||||
if (color_stack.next_index == 0) {
|
if (color_stack.count == 0) {
|
||||||
return print_to_file(f, "%s", console_normal);
|
return print_to_file(f, "%s", console_normal);
|
||||||
} else {
|
} else {
|
||||||
return print_to_file(f, "%s", color_stack[color_stack.next_index-1]);
|
return print_to_file(f, "%s", color_stack[color_stack.count-1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +477,6 @@ auto print_Str(FILE* f, String* str) -> s32 {
|
|||||||
|
|
||||||
auto print_str_line(FILE* f, char* str) -> s32 {
|
auto print_str_line(FILE* f, char* str) -> s32 {
|
||||||
u32 length = 0;
|
u32 length = 0;
|
||||||
char* str_cpy = str;
|
|
||||||
while (str[length] != '\0') {
|
while (str[length] != '\0') {
|
||||||
if (str[length] == '\n')
|
if (str[length] == '\n')
|
||||||
break;
|
break;
|
||||||
@@ -445,16 +486,19 @@ auto print_str_line(FILE* f, char* str) -> s32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void init_printer() {
|
void init_printer() {
|
||||||
|
#ifdef FTB_WINDOWS
|
||||||
|
// enable colored terminal output for windows
|
||||||
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
DWORD dwMode = 0;
|
||||||
|
GetConsoleMode(hOut, &dwMode);
|
||||||
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
SetConsoleMode(hOut, dwMode);
|
||||||
|
#endif
|
||||||
color_stack.alloc();
|
color_stack.alloc();
|
||||||
printer_map.alloc();
|
printer_map.alloc();
|
||||||
type_map.alloc();
|
type_map.alloc();
|
||||||
|
|
||||||
system_shutdown_hook << [](){
|
register_printer("spaces", print_spaces, Printer_Function_Type::_32b);
|
||||||
color_stack.dealloc();
|
|
||||||
printer_map.dealloc();
|
|
||||||
type_map.dealloc();
|
|
||||||
};
|
|
||||||
|
|
||||||
register_printer("u32", print_u32, Printer_Function_Type::_32b);
|
register_printer("u32", print_u32, Printer_Function_Type::_32b);
|
||||||
register_printer("u64", print_u64, Printer_Function_Type::_64b);
|
register_printer("u64", print_u64, Printer_Function_Type::_64b);
|
||||||
register_printer("bool", print_bool, Printer_Function_Type::_32b);
|
register_printer("bool", print_bool, Printer_Function_Type::_32b);
|
||||||
@@ -469,3 +513,9 @@ void init_printer() {
|
|||||||
register_printer("->Str", print_Str, Printer_Function_Type::_ptr);
|
register_printer("->Str", print_Str, Printer_Function_Type::_ptr);
|
||||||
register_printer("->char_line", print_str_line, Printer_Function_Type::_ptr);
|
register_printer("->char_line", print_str_line, Printer_Function_Type::_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deinit_printer() {
|
||||||
|
color_stack.dealloc();
|
||||||
|
printer_map.dealloc();
|
||||||
|
type_map.dealloc();
|
||||||
|
}
|
||||||
|
|||||||
+15
-9
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifdef _PROFILING
|
#ifdef PROFILING
|
||||||
|
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
# include <time.h>
|
# include <time.h>
|
||||||
|
# include "./platform.hpp"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef FTB_WINDOWS
|
||||||
# include <Windows.h>
|
# include <Windows.h>
|
||||||
#else
|
#else
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
@@ -47,14 +48,14 @@ bool QueryPerformanceCounter(int64_t *performance_count)
|
|||||||
|
|
||||||
|
|
||||||
struct Profiler {
|
struct Profiler {
|
||||||
#ifdef _MSC_VER
|
#ifdef FTB_WINDOWS
|
||||||
LARGE_INTEGER tmp_time;
|
LARGE_INTEGER tmp_time;
|
||||||
#else
|
#else
|
||||||
int64_t tmp_time;
|
int64_t tmp_time;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// same for all threads
|
// same for all threads
|
||||||
inline static char file_template[40] = "\0";
|
inline static char file_template[100] = "\0";
|
||||||
|
|
||||||
// thread local
|
// thread local
|
||||||
inline thread_local static bool is_initialized = false;
|
inline thread_local static bool is_initialized = false;
|
||||||
@@ -73,8 +74,13 @@ struct Profiler {
|
|||||||
tm* tm_i = localtime(&t);
|
tm* tm_i = localtime(&t);
|
||||||
|
|
||||||
// create folder
|
// create folder
|
||||||
#ifdef _MSC_VER
|
#ifdef FTB_WINDOWS
|
||||||
_mkdir("./profiler_reports/");
|
SECURITY_ATTRIBUTES sa;
|
||||||
|
sa.nLength = sizeof(sa);
|
||||||
|
sa.lpSecurityDescriptor = NULL;
|
||||||
|
sa.bInheritHandle = FALSE;
|
||||||
|
CreateDirectoryA("profiler_reports", &sa);
|
||||||
|
// _mkdir("./profiler_reports/");
|
||||||
#else
|
#else
|
||||||
mkdir("./profiler_reports/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
mkdir("./profiler_reports/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||||
#endif
|
#endif
|
||||||
@@ -97,7 +103,7 @@ struct Profiler {
|
|||||||
|
|
||||||
// initially write the performance frequency
|
// initially write the performance frequency
|
||||||
QueryPerformanceFrequency(&tmp_time);
|
QueryPerformanceFrequency(&tmp_time);
|
||||||
#ifdef _MSC_VER
|
#ifdef FTB_WINDOWS
|
||||||
fprintf(out_file, "%lld,,,,\n", tmp_time.QuadPart);
|
fprintf(out_file, "%lld,,,,\n", tmp_time.QuadPart);
|
||||||
#else
|
#else
|
||||||
fprintf(out_file, "%ld,,,,\n", tmp_time);
|
fprintf(out_file, "%ld,,,,\n", tmp_time);
|
||||||
@@ -106,7 +112,7 @@ struct Profiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QueryPerformanceCounter(&tmp_time);
|
QueryPerformanceCounter(&tmp_time);
|
||||||
#ifdef _MSC_VER
|
#ifdef FTB_WINDOWS
|
||||||
fprintf(out_file, "->,%lld,%s,%s,%d,%s,%s\n",
|
fprintf(out_file, "->,%lld,%s,%s,%d,%s,%s\n",
|
||||||
tmp_time.QuadPart, name, file,
|
tmp_time.QuadPart, name, file,
|
||||||
line, comment1, comment2);
|
line, comment1, comment2);
|
||||||
@@ -120,7 +126,7 @@ struct Profiler {
|
|||||||
~Profiler() {
|
~Profiler() {
|
||||||
call_depth -= 1;
|
call_depth -= 1;
|
||||||
QueryPerformanceCounter(&tmp_time);
|
QueryPerformanceCounter(&tmp_time);
|
||||||
#ifdef _MSC_VER
|
#ifdef FTB_WINDOWS
|
||||||
fprintf(out_file, "<-,%lld,,,,,\n", tmp_time.QuadPart);
|
fprintf(out_file, "<-,%lld,,,,,\n", tmp_time.QuadPart);
|
||||||
#else
|
#else
|
||||||
fprintf(out_file, "<-,%ld,,,,,\n", tmp_time);
|
fprintf(out_file, "<-,%ld,,,,,\n", tmp_time);
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import json
|
||||||
|
import csv
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
class FancyFloat(float):
|
||||||
|
def __repr__(self):
|
||||||
|
return format(Decimal(self), "f")
|
||||||
|
|
||||||
|
class JsonRpcEncoder(json.JSONEncoder):
|
||||||
|
def decimalize(self, val):
|
||||||
|
if isinstance(val, dict):
|
||||||
|
return {k:self.decimalize(v) for k,v in val.items()}
|
||||||
|
|
||||||
|
if isinstance(val, (list, tuple)):
|
||||||
|
return type(val)(self.decimalize(v) for v in val)
|
||||||
|
|
||||||
|
if isinstance(val, float):
|
||||||
|
return FancyFloat(val)
|
||||||
|
|
||||||
|
return val
|
||||||
|
|
||||||
|
def encode(self, val):
|
||||||
|
return super().encode(self.decimalize(val))
|
||||||
|
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
trace_events = []
|
||||||
|
call_stack = []
|
||||||
|
l = [p for p in os.listdir(sys.argv[1]) if p.endswith(".report")]
|
||||||
|
if len(l) == 0:
|
||||||
|
print("No reports are in this folder")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
file_name = l[0]
|
||||||
|
with open(file_name, "r") as in_file:
|
||||||
|
csv_reader = csv.reader(in_file, delimiter=',')
|
||||||
|
pf = 1
|
||||||
|
first_line = True
|
||||||
|
last_ts = -1;
|
||||||
|
for line in csv_reader:
|
||||||
|
if first_line:
|
||||||
|
pf = float(line[0]) / 1000
|
||||||
|
first_line = False
|
||||||
|
continue
|
||||||
|
if line[0] == "->":
|
||||||
|
call_stack.append(line)
|
||||||
|
elif line[0] == "<-":
|
||||||
|
call = call_stack.pop()
|
||||||
|
ts = float(call[1])
|
||||||
|
dur = (float(line[1])-ts)
|
||||||
|
dict = {
|
||||||
|
"pid": 1,
|
||||||
|
"tid": 1,
|
||||||
|
"ts" : ts,
|
||||||
|
"dur": dur,
|
||||||
|
"ph" : "X",
|
||||||
|
"name": call[2],
|
||||||
|
"args": {
|
||||||
|
"file": f"({call[3]}:{call[4]})",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if call[5]:
|
||||||
|
dict["args"]["info1"] = call[5]
|
||||||
|
if call[6]:
|
||||||
|
dict["args"]["info2"] = call[6]
|
||||||
|
trace_events.append(dict)
|
||||||
|
else:
|
||||||
|
print("invalid syntax")
|
||||||
|
break
|
||||||
|
with open(f"{file_name}.json", "w") as out_file:
|
||||||
|
out_file.write(json.dumps({"traceEvents": trace_events}, indent=4))
|
||||||
+607
@@ -0,0 +1,607 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "macros.hpp"
|
||||||
|
#include "types.hpp"
|
||||||
|
#include "print.hpp"
|
||||||
|
#include "bucket_allocator.hpp"
|
||||||
|
#include "arraylist.hpp"
|
||||||
|
#include "stacktrace.hpp"
|
||||||
|
|
||||||
|
namespace Scheduler {
|
||||||
|
|
||||||
|
// NOTE(Felix): since we want to be able to interpolate any data in
|
||||||
|
// principle, and the animation needs the start and end values, but the
|
||||||
|
// size of the stuff we want to interpolate may vary, we just give it a
|
||||||
|
// small chunk of memory to be stored
|
||||||
|
typedef s64 Data_Block[22];
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*Closure_F)(Data_Block);
|
||||||
|
typedef void (*Lambda_F)();
|
||||||
|
|
||||||
|
typedef f32 (*Shaper_F)(f32 t);
|
||||||
|
typedef void (*Interpolator_F)(void* from, f32 t, void* to, void* interpolant);
|
||||||
|
|
||||||
|
enum struct Interpolation_Type : u8 {
|
||||||
|
Lerp = 1 << 7,
|
||||||
|
Ease_In,
|
||||||
|
Ease_Out,
|
||||||
|
Ease_Middle,
|
||||||
|
Ease_In_And_Out
|
||||||
|
};
|
||||||
|
|
||||||
|
enum struct Interpolant_Type : u8 {
|
||||||
|
F32 = 1 << 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Scheduled_Animation_Create_Info {
|
||||||
|
float seconds_to_start;
|
||||||
|
float seconds_to_end;
|
||||||
|
|
||||||
|
void* interpolant;
|
||||||
|
Interpolant_Type interpolant_type;
|
||||||
|
|
||||||
|
void* from;
|
||||||
|
void* to;
|
||||||
|
|
||||||
|
Interpolation_Type interpolation_type = Interpolation_Type::Lerp;
|
||||||
|
const char* name = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum struct Function_Type {
|
||||||
|
Closure,
|
||||||
|
Lambda
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Action_Create_Info {
|
||||||
|
Function_Type type;
|
||||||
|
union {
|
||||||
|
Lambda_F lambda;
|
||||||
|
Closure_F closure;
|
||||||
|
};
|
||||||
|
void* param = nullptr;
|
||||||
|
u32 param_size = 0;
|
||||||
|
const char* name = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Scheduled_Action_Create_Info {
|
||||||
|
float seconds_to_run;
|
||||||
|
Action_Create_Info action;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Action {
|
||||||
|
Function_Type type;
|
||||||
|
union {
|
||||||
|
Lambda_F lambda;
|
||||||
|
Closure_F closure;
|
||||||
|
};
|
||||||
|
Data_Block param;
|
||||||
|
Action* next;
|
||||||
|
u64 creation_stamp;
|
||||||
|
bool already_ran;
|
||||||
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
|
const char* name;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Scheduled_Action {
|
||||||
|
f32 seconds_to_run;
|
||||||
|
Action action;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Scheduled_Animation {
|
||||||
|
Interpolation_Type interpolation_type;
|
||||||
|
Interpolant_Type interpolant_type;
|
||||||
|
|
||||||
|
f32 seconds_to_start;
|
||||||
|
f32 seconds_to_end;
|
||||||
|
|
||||||
|
void* interpolant;
|
||||||
|
|
||||||
|
Data_Block from;
|
||||||
|
Data_Block to;
|
||||||
|
|
||||||
|
Action* next;
|
||||||
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
|
const char* name;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
enum struct Schedulee_Type : u8 {
|
||||||
|
None,
|
||||||
|
Action,
|
||||||
|
Animation,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Action_Or_Animation {
|
||||||
|
Schedulee_Type type;
|
||||||
|
union {
|
||||||
|
Action* action;
|
||||||
|
Scheduled_Animation* animation;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// For user defined shapers t -> t
|
||||||
|
Shaper_F _shapers[127];
|
||||||
|
// Interpolators for user types
|
||||||
|
Interpolator_F _interpolators[127];
|
||||||
|
size_t _interpolatee_sizes[127];
|
||||||
|
|
||||||
|
// Per reset cycle:
|
||||||
|
// PING
|
||||||
|
Bucket_Allocator<Scheduled_Animation> active_animations_1;
|
||||||
|
Bucket_Allocator<Scheduled_Action> scheduled_actions_1;
|
||||||
|
Bucket_Allocator<Action> chained_actions_1;
|
||||||
|
// PONG
|
||||||
|
Bucket_Allocator<Scheduled_Animation> active_animations_2;
|
||||||
|
Bucket_Allocator<Scheduled_Action> scheduled_actions_2;
|
||||||
|
Bucket_Allocator<Action> chained_actions_2;
|
||||||
|
|
||||||
|
Bucket_Allocator<Scheduled_Animation>* active_animations;
|
||||||
|
Bucket_Allocator<Scheduled_Action>* scheduled_actions;
|
||||||
|
Bucket_Allocator<Action>* chained_actions;
|
||||||
|
|
||||||
|
Bucket_Allocator<Scheduled_Animation>* future_active_animations;
|
||||||
|
Bucket_Allocator<Scheduled_Action>* future_scheduled_actions;
|
||||||
|
Bucket_Allocator<Action>* future_chained_actions;
|
||||||
|
|
||||||
|
// Per Tick:
|
||||||
|
// if something is deleted while iterating over them
|
||||||
|
Array_List<Scheduled_Animation*> _animations_marked_for_deletion;
|
||||||
|
Array_List<Scheduled_Action*> _actions_marked_for_deletion;
|
||||||
|
|
||||||
|
Array_List<Action*> _chained_actions_to_be_run_after_iteration;
|
||||||
|
|
||||||
|
bool _is_iterating = false;
|
||||||
|
bool _should_reset = false;
|
||||||
|
bool _should_stop_iterating = false;
|
||||||
|
u64 _action_stamp_counter = 0;
|
||||||
|
|
||||||
|
auto init() -> void {
|
||||||
|
active_animations_1.alloc();
|
||||||
|
scheduled_actions_1.alloc();
|
||||||
|
chained_actions_1.alloc();
|
||||||
|
|
||||||
|
active_animations_2.alloc();
|
||||||
|
scheduled_actions_2.alloc();
|
||||||
|
chained_actions_2.alloc();
|
||||||
|
|
||||||
|
active_animations = &active_animations_1;
|
||||||
|
scheduled_actions = &scheduled_actions_1;
|
||||||
|
chained_actions = &chained_actions_1;
|
||||||
|
|
||||||
|
future_active_animations = &active_animations_2;
|
||||||
|
future_scheduled_actions = &scheduled_actions_2;
|
||||||
|
future_chained_actions = &chained_actions_2;
|
||||||
|
|
||||||
|
|
||||||
|
_animations_marked_for_deletion.alloc();
|
||||||
|
_actions_marked_for_deletion.alloc();
|
||||||
|
_chained_actions_to_be_run_after_iteration.alloc(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto deinit() -> void {
|
||||||
|
active_animations_1.dealloc();
|
||||||
|
scheduled_actions_1.dealloc();
|
||||||
|
chained_actions_1.dealloc();
|
||||||
|
|
||||||
|
active_animations_2.dealloc();
|
||||||
|
scheduled_actions_2.dealloc();
|
||||||
|
chained_actions_2.dealloc();
|
||||||
|
|
||||||
|
_animations_marked_for_deletion.dealloc();
|
||||||
|
_actions_marked_for_deletion.dealloc();
|
||||||
|
_chained_actions_to_be_run_after_iteration.dealloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto register_shaper(Shaper_F f, Interpolation_Type t) {
|
||||||
|
_shapers[(u8)t] = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto register_interpolator(Interpolator_F f, Interpolant_Type t, size_t size_of_interpolant) {
|
||||||
|
_interpolatee_sizes[(u8)t] = size_of_interpolant;
|
||||||
|
_interpolators[(u8)t] = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto schedule_animation(Scheduled_Animation_Create_Info aci) -> Scheduled_Animation* {
|
||||||
|
Scheduled_Animation* anim;
|
||||||
|
if (_should_reset) {
|
||||||
|
anim = future_active_animations->allocate();
|
||||||
|
} else {
|
||||||
|
anim = active_animations->allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
anim->next = nullptr;
|
||||||
|
|
||||||
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
|
anim->name = aci.name;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
anim->interpolation_type = aci.interpolation_type;
|
||||||
|
anim->interpolant_type = aci.interpolant_type;
|
||||||
|
|
||||||
|
anim->seconds_to_start = aci.seconds_to_start;
|
||||||
|
anim->seconds_to_end = aci.seconds_to_end;
|
||||||
|
|
||||||
|
anim->interpolant = aci.interpolant;
|
||||||
|
|
||||||
|
u32 data_size;
|
||||||
|
switch(anim->interpolant_type) {
|
||||||
|
case Interpolant_Type::F32: data_size = sizeof(f32); break;
|
||||||
|
default: {
|
||||||
|
data_size = _interpolatee_sizes[(u8)(anim->interpolant_type)];
|
||||||
|
panic_if(data_size == 0, "Interpolatee (%d) size was 0 (was it initialized correctly)?",
|
||||||
|
anim->interpolant_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&anim->from, aci.from, data_size);
|
||||||
|
memcpy(&anim->to, aci.to, data_size);
|
||||||
|
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto advance_single_animation(Scheduled_Animation* anim) -> void {
|
||||||
|
// if not yet started, skip
|
||||||
|
if (anim->seconds_to_start > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// otherwise run it:
|
||||||
|
f32 perf_diff = anim->seconds_to_end - anim->seconds_to_start;
|
||||||
|
f32 perf_inside = -anim->seconds_to_start;
|
||||||
|
f64 t = 1.0 * perf_inside / perf_diff;
|
||||||
|
|
||||||
|
switch (anim->interpolation_type) {
|
||||||
|
case Interpolation_Type::Lerp: break;
|
||||||
|
case Interpolation_Type::Ease_In: {
|
||||||
|
t *= t;
|
||||||
|
} break;
|
||||||
|
case Interpolation_Type::Ease_Out: {
|
||||||
|
t = -(t * (t - 2));
|
||||||
|
} break;
|
||||||
|
case Interpolation_Type::Ease_In_And_Out: {
|
||||||
|
// NOTE(Felix): yes -- Mon Dec 7 11:47:34 2020
|
||||||
|
t = (t < 0.5) ?
|
||||||
|
+2 * t * t :
|
||||||
|
-2 * (t * (t - 2)) - 1;
|
||||||
|
} break;
|
||||||
|
case Interpolation_Type::Ease_Middle: {
|
||||||
|
// t = (t < 0.5) ?
|
||||||
|
// -2 * t * (t - 1) :
|
||||||
|
// +2 * t * (t - 1) + 1;
|
||||||
|
t = 4.0f / 5.0f * t*t*t - 6.0f/5.0f *t*t + 7.0f/5.0f * t;
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
// try user supported shaper
|
||||||
|
Shaper_F shaper = _shapers[(u8)anim->interpolant_type];
|
||||||
|
|
||||||
|
panic_if(shaper == nullptr,
|
||||||
|
"Shaper function for type (%d) was nullptr (was it initialized correctly)?",
|
||||||
|
anim->interpolation_type);
|
||||||
|
|
||||||
|
t = shaper(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(anim->interpolant_type) {
|
||||||
|
case Interpolant_Type::F32: {
|
||||||
|
f32 from = *((f32*)&anim->from);
|
||||||
|
f32 to = *((f32*)&anim->to);
|
||||||
|
*((f32*)anim->interpolant) = from + (to - from) * t;
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
// try user supported interpolator
|
||||||
|
Interpolator_F interpolator = _interpolators[(u8)anim->interpolant_type];
|
||||||
|
|
||||||
|
panic_if(interpolator == nullptr,
|
||||||
|
"Interpolator function for type (%d) was nullptr (was it initialized correctly)?",
|
||||||
|
anim->interpolant_type);
|
||||||
|
|
||||||
|
interpolator(&anim->from, t, &anim->to, anim->interpolant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto _init_action(Action* action, Action_Create_Info aci) -> void {
|
||||||
|
action->next = nullptr;
|
||||||
|
#ifdef FTB_INTERNAL_DEBUG
|
||||||
|
action->name = aci.name;
|
||||||
|
#endif
|
||||||
|
action->creation_stamp = _action_stamp_counter;
|
||||||
|
|
||||||
|
++_action_stamp_counter;
|
||||||
|
action->already_ran = false;
|
||||||
|
|
||||||
|
if (aci.param) {
|
||||||
|
if(aci.param_size > sizeof(Data_Block)) {
|
||||||
|
panic("%llu (sizeof(Data_Block)) < %u (aci.param_size)",
|
||||||
|
sizeof(Data_Block), aci.param_size);
|
||||||
|
}
|
||||||
|
action->type = Function_Type::Closure;
|
||||||
|
action->closure = aci.closure;
|
||||||
|
memcpy(&action->param, aci.param, aci.param_size);
|
||||||
|
} else {
|
||||||
|
action->type = Function_Type::Lambda;
|
||||||
|
action->lambda = aci.lambda;
|
||||||
|
memset(&action->param, 0, sizeof(Data_Block));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aci.type == Function_Type::Lambda) action->lambda = aci.lambda;
|
||||||
|
else if (aci.type == Function_Type::Closure) action->closure = aci.closure;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auto schedule_action(Scheduled_Action_Create_Info aci) -> Scheduled_Action* {
|
||||||
|
Scheduled_Action* scheduled_action;
|
||||||
|
if (_should_reset) {
|
||||||
|
scheduled_action = future_scheduled_actions->allocate();
|
||||||
|
} else {
|
||||||
|
scheduled_action = scheduled_actions->allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduled_action->seconds_to_run = aci.seconds_to_run;
|
||||||
|
_init_action(&scheduled_action->action, aci.action);
|
||||||
|
debug_log("scheduling action %s %d", aci.action.name, scheduled_action->action.creation_stamp);
|
||||||
|
return scheduled_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto _actually_reset() {
|
||||||
|
debug_log("HARD RESET SCHEDULER");
|
||||||
|
_should_reset = false;
|
||||||
|
active_animations->clear();
|
||||||
|
scheduled_actions->clear();
|
||||||
|
chained_actions->clear();
|
||||||
|
_animations_marked_for_deletion.clear();
|
||||||
|
_actions_marked_for_deletion.clear();
|
||||||
|
|
||||||
|
// swap ping pong
|
||||||
|
Bucket_Allocator<Scheduled_Animation>* t_active_animations = active_animations;
|
||||||
|
Bucket_Allocator<Scheduled_Action>* t_scheduled_actions = scheduled_actions;
|
||||||
|
Bucket_Allocator<Action>* t_chained_actions = chained_actions;
|
||||||
|
|
||||||
|
active_animations = future_active_animations;
|
||||||
|
scheduled_actions = future_scheduled_actions;
|
||||||
|
chained_actions = future_chained_actions;
|
||||||
|
|
||||||
|
future_active_animations = t_active_animations;
|
||||||
|
future_scheduled_actions = t_scheduled_actions;
|
||||||
|
future_chained_actions = t_chained_actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto reset() -> void {
|
||||||
|
if (_is_iterating) {
|
||||||
|
debug_log("SOFT RESET Scheduler");
|
||||||
|
_should_reset = true;
|
||||||
|
future_active_animations->clear();
|
||||||
|
future_scheduled_actions->clear();
|
||||||
|
future_chained_actions->clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_actually_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chain_action(Scheduled_Animation* existing_animation, Action_Create_Info aci) -> Action* {
|
||||||
|
Action* chain_action;
|
||||||
|
if (_should_reset) {
|
||||||
|
chain_action = future_chained_actions->allocate();
|
||||||
|
} else {
|
||||||
|
chain_action = chained_actions->allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
_init_action(chain_action, aci);
|
||||||
|
|
||||||
|
existing_animation->next = chain_action;
|
||||||
|
return chain_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto chain_action(Action* existing_action, Action_Create_Info aci) -> Action* {
|
||||||
|
Action* chain_action;
|
||||||
|
if (_should_reset) {
|
||||||
|
chain_action = future_chained_actions->allocate();
|
||||||
|
} else {
|
||||||
|
chain_action = chained_actions->allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
_init_action(chain_action, aci);
|
||||||
|
|
||||||
|
existing_action->next = chain_action;
|
||||||
|
return chain_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto chain_action(Action_Or_Animation aoa, Action_Create_Info aci) -> Action* {
|
||||||
|
if (aoa.type == Schedulee_Type::Action)
|
||||||
|
return chain_action(aoa.action, aci);
|
||||||
|
else if (aoa.type == Schedulee_Type::Animation)
|
||||||
|
return chain_action(aoa.animation, aci);
|
||||||
|
else if (aoa.type == Schedulee_Type::None) {
|
||||||
|
Scheduled_Action* sa = schedule_action({
|
||||||
|
.seconds_to_run = 0.0f,
|
||||||
|
.action { aci }
|
||||||
|
});
|
||||||
|
return &sa->action;
|
||||||
|
} else {
|
||||||
|
panic("unknown Schedulee type");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto execute_action(Action* action) -> void {
|
||||||
|
debug_log("running action %s %d", action->name, action->creation_stamp);
|
||||||
|
|
||||||
|
action->already_ran = true;
|
||||||
|
if (action->type == Function_Type::Closure) {
|
||||||
|
action->closure(action->param);
|
||||||
|
} else {
|
||||||
|
action->lambda();
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_log("finished running action %s %d", action->name, action->creation_stamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto handle_chained_action(Action* action) -> void {
|
||||||
|
debug_log("Handling chained actions");
|
||||||
|
while (action) {
|
||||||
|
debug_log("RUNNING CHAINED %s %d", action->name, action->creation_stamp);
|
||||||
|
execute_action(action);
|
||||||
|
|
||||||
|
debug_log("DELETING action %s %d", action->name, action->creation_stamp);
|
||||||
|
chained_actions->free_object(action);
|
||||||
|
action = action->next;
|
||||||
|
|
||||||
|
if (_should_stop_iterating) break;
|
||||||
|
}
|
||||||
|
debug_log("Chained actions done");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto run_pending_actions_and_reset() -> void {
|
||||||
|
Auto_Array_List<Action*> pending_actions(16);
|
||||||
|
|
||||||
|
debug_log("%{color<}Running pending actions:", console_cyan);
|
||||||
|
scheduled_actions->for_each([&](Scheduled_Action* s_action) {
|
||||||
|
if (!s_action->action.already_ran) {
|
||||||
|
pending_actions.append(&s_action->action);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
active_animations->for_each([&](Scheduled_Animation* s_animation) {
|
||||||
|
if (s_animation->next && !s_animation->next->already_ran) {
|
||||||
|
pending_actions.append(s_animation->next);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
qsort(pending_actions.data,
|
||||||
|
pending_actions.count,
|
||||||
|
sizeof(pending_actions.data[0]),
|
||||||
|
[] (const void* a1, const void* a2) -> int {
|
||||||
|
return (*((Action**)(a1)))->creation_stamp - (*((Action**)(a2)))->creation_stamp;
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto action : pending_actions) {
|
||||||
|
execute_action(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_log("pending_actions done%{>color}");
|
||||||
|
_should_stop_iterating = true;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto update_all(f32 delta_time) -> void {
|
||||||
|
|
||||||
|
// advance animations and collect due actions
|
||||||
|
{
|
||||||
|
active_animations->for_each([=](Scheduled_Animation* anim) {
|
||||||
|
anim->seconds_to_start -= delta_time;
|
||||||
|
anim->seconds_to_end -= delta_time;
|
||||||
|
|
||||||
|
advance_single_animation(anim);
|
||||||
|
|
||||||
|
if (anim->seconds_to_end <= 0) {
|
||||||
|
// NOTE(Felix): if already finished snap the value to its target
|
||||||
|
// and delete it
|
||||||
|
switch (anim->interpolant_type) {
|
||||||
|
case Interpolant_Type::F32: *(f32*)anim->interpolant = *(f32*)anim->to; break;
|
||||||
|
default: {
|
||||||
|
size_t interpolantee_size = _interpolatee_sizes[(u8)anim->interpolant_type];
|
||||||
|
panic_if(interpolantee_size == 0,
|
||||||
|
"Interpolatee (%d) size was 0 (was it initialized correctly)?",
|
||||||
|
anim->interpolant_type);
|
||||||
|
|
||||||
|
memcpy(anim->interpolant, anim->to, interpolantee_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_animations_marked_for_deletion.append(anim);
|
||||||
|
// NOTE(Felix): Don't actually run the next here, queue it
|
||||||
|
// up for after the iteration, see note below.
|
||||||
|
if (anim->next) {
|
||||||
|
_chained_actions_to_be_run_after_iteration.append(anim->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
scheduled_actions->for_each([=](Scheduled_Action* action) {
|
||||||
|
action->seconds_to_run -= delta_time;
|
||||||
|
if (action->seconds_to_run <= 0) {
|
||||||
|
_chained_actions_to_be_run_after_iteration.append(&action->action);
|
||||||
|
_actions_marked_for_deletion.append(action);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(Felix): The reason why we iterate over the chained actions like
|
||||||
|
// this: Imagine the following scenario: We schedule two animations
|
||||||
|
// that take the same time to run should run in parallel. So what you
|
||||||
|
// do for the first animation is put their parenting action (not the
|
||||||
|
// unparenting action) as the last action in the current game state
|
||||||
|
// and schedule their animation and then chain the unparenting action
|
||||||
|
// to the animation. The gamestate however only knows about the
|
||||||
|
// parenting action, so that the next thing that is scheduled runs
|
||||||
|
// parallel to it. For the second animation, the parenting action is
|
||||||
|
// scheduled onto the parenting action of the first animation, the
|
||||||
|
// animation is scheduled, and then also the unparenting action is
|
||||||
|
// chained to the animation. This time we set the Game_State
|
||||||
|
// last_scheduled to the unparenting action, so that no further
|
||||||
|
// animation will happen in parallel. Now imagine we chain some
|
||||||
|
// animation to the game state, that involves the animation of the
|
||||||
|
// first object. It can happen, when iterating through the animations,
|
||||||
|
// that we iterate first over the second animation, would then run
|
||||||
|
// their chained actions, in which we would animate the first object.
|
||||||
|
// This is bad, as they are not finished yet, their unparenting action
|
||||||
|
// did not run yet. Now we "solve" this by iterating breadth first
|
||||||
|
// over the actions.
|
||||||
|
if (_chained_actions_to_be_run_after_iteration.count > 1) {
|
||||||
|
qsort(_chained_actions_to_be_run_after_iteration.data,
|
||||||
|
_chained_actions_to_be_run_after_iteration.count,
|
||||||
|
sizeof(_chained_actions_to_be_run_after_iteration.data[0]),
|
||||||
|
[] (const void* a1, const void* a2) -> int {
|
||||||
|
return (*((Action**)(a1)))->creation_stamp - (*((Action**)(a2)))->creation_stamp;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// excute all due actions:
|
||||||
|
{
|
||||||
|
_is_iterating = true;
|
||||||
|
_should_stop_iterating = false;
|
||||||
|
for (Action* action : _chained_actions_to_be_run_after_iteration) {
|
||||||
|
if (action->already_ran) continue;
|
||||||
|
|
||||||
|
execute_action(action);
|
||||||
|
|
||||||
|
if (_should_stop_iterating) break;
|
||||||
|
|
||||||
|
handle_chained_action(action->next);
|
||||||
|
|
||||||
|
if (_should_stop_iterating) break;
|
||||||
|
}
|
||||||
|
_is_iterating = false;
|
||||||
|
_chained_actions_to_be_run_after_iteration.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE(Felix): if Scheduler::reset was called in an action (happens
|
||||||
|
// when scheduling a level switch), then don't actually reset
|
||||||
|
// everyting, but only set _should_reset. Because if we would actually
|
||||||
|
// clear all the bucket allocators, we would then anyway call
|
||||||
|
// free_object on them down when we process the _marked_for_deletion
|
||||||
|
// things, so we would have stuff in the free list that is not
|
||||||
|
// actually allocated
|
||||||
|
if (_should_reset) {
|
||||||
|
_actually_reset();
|
||||||
|
} else {
|
||||||
|
// NOTE(Felix): Don't free stuff from the bucket_allocators while
|
||||||
|
// iterating over them, as this appends the pointers to the free_list,
|
||||||
|
// which then is no longer sorted, which destroys the mechanism to
|
||||||
|
// check if a bucket is active or freed, so for_each will be called
|
||||||
|
// for buckets that are no longer alive. -Felix Dec 18 2020
|
||||||
|
for (auto anim : _animations_marked_for_deletion) {
|
||||||
|
active_animations->free_object(anim);
|
||||||
|
}
|
||||||
|
for (auto action : _actions_marked_for_deletion) {
|
||||||
|
scheduled_actions->free_object(action);
|
||||||
|
}
|
||||||
|
_animations_marked_for_deletion.clear();
|
||||||
|
_actions_marked_for_deletion.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "platform.hpp"
|
||||||
|
#include "allocation_stats.hpp"
|
||||||
|
|
||||||
|
#if defined FTB_WINDOWS
|
||||||
|
# include <dbghelp.h>
|
||||||
|
#else
|
||||||
|
# ifdef FTB_LINUX_STACK_TRACE_USE_GDB
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <sys/wait.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <sys/prctl.h>
|
||||||
|
# else
|
||||||
|
# include <execinfo.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
# include "stdio.h"
|
||||||
|
# include "stdlib.h"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto print_stacktrace() -> void {
|
||||||
|
#if defined FTB_WINDOWS
|
||||||
|
printf("Stacktrace: \n");
|
||||||
|
unsigned int i;
|
||||||
|
void * stack[ 100 ];
|
||||||
|
HANDLE process;
|
||||||
|
SYMBOL_INFO * symbol;
|
||||||
|
symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
|
||||||
|
symbol->MaxNameLen = 255;
|
||||||
|
symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
|
||||||
|
|
||||||
|
unsigned short frames;
|
||||||
|
frames = CaptureStackBackTrace( 1, 100, stack, NULL );
|
||||||
|
|
||||||
|
process = GetCurrentProcess();
|
||||||
|
SymInitialize( process, NULL, TRUE );
|
||||||
|
|
||||||
|
for( i = 0; i < frames; i++ ) {
|
||||||
|
SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol );
|
||||||
|
printf( " %3i: %s\n", frames - i - 1, symbol->Name);
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
#else
|
||||||
|
#ifdef FTB_LINUX_STACK_TRACE_USE_GDB
|
||||||
|
printf("Stacktrace: \n");
|
||||||
|
char pid_buf[30];
|
||||||
|
sprintf(pid_buf, "%d", getpid());
|
||||||
|
char name_buf[512];
|
||||||
|
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
|
||||||
|
prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
|
||||||
|
int child_pid = fork();
|
||||||
|
if (!child_pid) {
|
||||||
|
dup2(2,1); // redirect output to stderr - edit: unnecessary?
|
||||||
|
execl("/usr/bin/gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
|
||||||
|
abort(); /* If gdb failed to start */
|
||||||
|
} else {
|
||||||
|
waitpid(child_pid,NULL,0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// NOTE(Felix): Don't forget to compile with "-rdynamic"
|
||||||
|
printf("Stacktrace (this is unmagled -- sorry): \n");
|
||||||
|
char **strings;
|
||||||
|
size_t i, size;
|
||||||
|
enum Constexpr { MAX_SIZE = 1024 };
|
||||||
|
void *array[MAX_SIZE];
|
||||||
|
size = backtrace(array, MAX_SIZE);
|
||||||
|
strings = backtrace_symbols(array, size);
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
printf(" %3lu: %s\n", size - i - 1, strings[i]);
|
||||||
|
puts("");
|
||||||
|
ftb_free(strings);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
#define _CRT_SECURE_NO_WARNINGS
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "./types.hpp"
|
|
||||||
#include "./hooks.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
#include "./error.hpp"
|
|
||||||
#include "./print.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
int print_dots(FILE* f) {
|
|
||||||
return print_to_file(f, "...");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_printer() {
|
|
||||||
// u32 arr[] = {1,2,3,4,1,1,3};
|
|
||||||
// f32 f_arr[] = {1.1,2.1,3.2};
|
|
||||||
|
|
||||||
// init_printer();
|
|
||||||
// register_printer("dots", print_dots, Printer_Function_Type::_void);
|
|
||||||
|
|
||||||
// u32 u1 = -1;
|
|
||||||
// u64 u2 = -1;
|
|
||||||
|
|
||||||
// char* str;
|
|
||||||
// print_to_string(&str, " - %{dots[5]} %{->} <> %{->,2}\n", &u1, &arr, nullptr);
|
|
||||||
// print("---> %{->char}", str);
|
|
||||||
|
|
||||||
// print(" - %{dots[3]}\n");
|
|
||||||
// print(" - %{u32} %{u64}\n", u1, u2);
|
|
||||||
// print(" - %{u32} %{u32} %{u32}\n", 2, 5, 7);
|
|
||||||
// print(" - %{f32} %{f32} %{f32}\n", 2.0, 5.0, 7.0);
|
|
||||||
// print(" - %{u32} %{bool} %{->char}\n", 2, true, "hello");
|
|
||||||
// print(" - %{f32[3]}\n", f_arr);
|
|
||||||
// print(" - %{f32,3}\n", 44.9, 55.1, 66.2);
|
|
||||||
// print(" - %{u32[5]}\n", arr);
|
|
||||||
// print(" - %{u32[*]}\n", arr, 4);
|
|
||||||
// print(" - %{u32,5}\n", 1,2,3,4,1,2);
|
|
||||||
// print(" - %{unknown%d}\n", 1);
|
|
||||||
// print(" - %{s32,3}\n", -1,200,-300);
|
|
||||||
// print(" - %{->} <> %{->,2}\n", &u1, &arr, nullptr);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 main(s32 argc, char* argv[]) {
|
|
||||||
|
|
||||||
// test_printer();
|
|
||||||
|
|
||||||
init_printer();
|
|
||||||
// create_generic_error("nothing to lex was found:\n"
|
|
||||||
// " in %{color<}%{->char}%{>color}\n"
|
|
||||||
// " at %{color<}%{->char}%{>color}\n"
|
|
||||||
// "bottom text\n",
|
|
||||||
// console_green,
|
|
||||||
// "some file name",
|
|
||||||
// console_cyan,
|
|
||||||
// "yesssssss");
|
|
||||||
|
|
||||||
create_error(__FUNCTION__, __FILE__, __LINE__,
|
|
||||||
make_heap_string("generic"),
|
|
||||||
"nothing to lex was found:\n"
|
|
||||||
" in %{color<}%{->char}%{>color}\n"
|
|
||||||
" at %{color<}%{->char}%{>color}\n"
|
|
||||||
"bottom text\n",
|
|
||||||
console_green,
|
|
||||||
"some file name",
|
|
||||||
console_cyan,
|
|
||||||
"yesssssss");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
+5
-4
@@ -1,8 +1,9 @@
|
|||||||
#include "./types.hpp"
|
#include "./types.hpp"
|
||||||
|
#include "./allocation_stats.hpp"
|
||||||
|
|
||||||
typedef s32 testresult;
|
typedef s32 testresult;
|
||||||
|
|
||||||
#define epsilon 2.2204460492503131E-16
|
#define float_epsilon 2.2204460492503131E-16
|
||||||
#define pass 1
|
#define pass 1
|
||||||
#define fail 0
|
#define fail 0
|
||||||
|
|
||||||
@@ -57,13 +58,13 @@ typedef s32 testresult;
|
|||||||
} \
|
} \
|
||||||
|
|
||||||
#define assert_equal_f64(variable, value) \
|
#define assert_equal_f64(variable, value) \
|
||||||
if (fabsl((f64)variable - (f64)value) > epsilon) { \
|
if (fabsl((f64)variable - (f64)value) > float_epsilon) { \
|
||||||
print_assert_equal_fail(variable, value, f64, "%{f64}"); \
|
print_assert_equal_fail(variable, value, f64, "%{f64}"); \
|
||||||
return fail; \
|
return fail; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define assert_not_equal_f64(variable, value) \
|
#define assert_not_equal_f64(variable, value) \
|
||||||
if (fabsl((f64)variable - (f64)value) <= epsilon) { \
|
if (fabsl((f64)variable - (f64)value) <= float_epsilon) { \
|
||||||
print_assert_not_equal_fail(variable, value, f64, "%{f64}"); \
|
print_assert_not_equal_fail(variable, value, f64, "%{f64}"); \
|
||||||
return fail; \
|
return fail; \
|
||||||
}
|
}
|
||||||
@@ -87,7 +88,7 @@ typedef s32 testresult;
|
|||||||
fputs((i%3==1)? "." : " ", stdout); \
|
fputs((i%3==1)? "." : " ", stdout); \
|
||||||
fputs(console_red "failed\n" console_normal, stdout); \
|
fputs(console_red "failed\n" console_normal, stdout); \
|
||||||
if(error) { \
|
if(error) { \
|
||||||
free(error); \
|
ftb_free(error); \
|
||||||
error = nullptr; \
|
error = nullptr; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
rmdir bin /s /q 2>NUL
|
||||||
|
mkdir bin 2>NUL
|
||||||
|
|
||||||
|
set EXE_RAW=test
|
||||||
|
set BINDIR_RAW=bin
|
||||||
|
set SRC=main.cpp
|
||||||
|
|
||||||
|
set EXE_WIN=%EXE_RAW%.exe
|
||||||
|
set EXE_LINUX=%EXE_RAW%
|
||||||
|
set BINDIR_WIN=.\%BINDIR_RAW%
|
||||||
|
set BINDIR_LINUX=./%BINDIR_RAW%
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo clang:
|
||||||
|
clang -g -std=c++17 %SRC% -o %BINDIR_WIN%\clang_%EXE_WIN%
|
||||||
|
%BINDIR_WIN%\clang_%EXE_WIN%
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo g++:
|
||||||
|
g++ -std=c++17 %SRC% -o %BINDIR_WIN%\g++_%EXE_WIN%
|
||||||
|
%BINDIR_WIN%\g++_%EXE_WIN%
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo cl:
|
||||||
|
cl %SRC% /std:c++latest /nologo /Zi /Fd: %BINDIR_WIN%\cl_%EXE_WIN%.pdb /Fo: %BINDIR_WIN%\ /Fe: %BINDIR_WIN%\cl_%EXE_WIN% /wd4090 1>NUL
|
||||||
|
%BINDIR_WIN%\cl_%EXE_WIN%
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo bash_clang:
|
||||||
|
bash -c "clang++ --std=c++17 %SRC% -o %BINDIR_LINUX%/bash_clang_%EXE_LINUX% && %BINDIR_LINUX%/bash_clang_%EXE_LINUX%"
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo bash_g++:
|
||||||
|
bash -c "g++ --std=c++17 %SRC% -o %BINDIR_LINUX%/bash_g++_%EXE_LINUX% && %BINDIR_LINUX%/bash_g++_%EXE_LINUX%"
|
||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
TIMEFORMAT=%3lR
|
||||||
|
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||||
|
pushd $SCRIPTPATH > /dev/null
|
||||||
|
|
||||||
|
# _DEBUG
|
||||||
|
# time g++ -fpermissive src/main.cpp -g -o ./bin/slime --std=c++17 || exit 1
|
||||||
|
time clang++ -rdynamic -D_DEBUG -D_PROFILING -fpermissive main.cpp -g -o ./ftb --std=c++17 || exit 1
|
||||||
|
# time clang++ -D_DEBUG -D_PROFILING -fpermissive cpu_info.cpp -g -o ./cpu_info --std=c++17 || exit 1
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
# time valgrind --track-origins=yes --leak-check=full --show-leak-kinds=all ./ftb
|
||||||
|
time ./ftb
|
||||||
|
# time ./cpu_info
|
||||||
|
|
||||||
|
popd > /dev/null
|
||||||
|
unset TIMEFORMAT
|
||||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,240 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "../cpu_info.hpp"
|
||||||
|
|
||||||
|
auto print_full_cpu_info() -> void {
|
||||||
|
Cpu_Info info;
|
||||||
|
get_cpu_info(&info);
|
||||||
|
printf("-------------------\n");
|
||||||
|
printf(" CPU INFO \n");
|
||||||
|
printf("-------------------\n");
|
||||||
|
printf("vendor: %s\n", info.vendor);
|
||||||
|
printf("brand: %s\n", info.brand);
|
||||||
|
printf("-------------------\n");
|
||||||
|
printf("Edx_1_Feature_Flags\n");
|
||||||
|
printf("-------------------\n");
|
||||||
|
printf("fpu: %s // Onboard x87 FPU\n", query_cpu_feature(&info, Edx_1_Feature_Flags::fpu) ? "yes" : "no ");
|
||||||
|
printf("vme: %s // Virtual 8086 mode extensions (such as VIF, VIP, PIV)\n", query_cpu_feature(&info, Edx_1_Feature_Flags::vme) ? "yes" : "no ");
|
||||||
|
printf("de: %s // Debugging extensions (CR4 bit 3)\n", query_cpu_feature(&info, Edx_1_Feature_Flags::de) ? "yes" : "no ");
|
||||||
|
printf("pse: %s // Page Size Extension\n", query_cpu_feature(&info, Edx_1_Feature_Flags::pse) ? "yes" : "no ");
|
||||||
|
printf("tsc: %s // Time Stamp Counter\n", query_cpu_feature(&info, Edx_1_Feature_Flags::tsc) ? "yes" : "no ");
|
||||||
|
printf("msr: %s // Model-specific registers\n", query_cpu_feature(&info, Edx_1_Feature_Flags::msr) ? "yes" : "no ");
|
||||||
|
printf("pae: %s // Physical Address Extension\n", query_cpu_feature(&info, Edx_1_Feature_Flags::pae) ? "yes" : "no ");
|
||||||
|
printf("mce: %s // Machine Check Exception\n", query_cpu_feature(&info, Edx_1_Feature_Flags::mce) ? "yes" : "no ");
|
||||||
|
printf("cx8: %s // CMPXCHG8 (compare-and-swap) instruction\n", query_cpu_feature(&info, Edx_1_Feature_Flags::cx8) ? "yes" : "no ");
|
||||||
|
printf("apic: %s // Onboard Advanced Programmable Interrupt Controller\n", query_cpu_feature(&info, Edx_1_Feature_Flags::apic) ? "yes" : "no ");
|
||||||
|
printf("_resv1: %s // (reserved)\n", query_cpu_feature(&info, Edx_1_Feature_Flags::_resv1) ? "yes" : "no ");
|
||||||
|
printf("sep: %s // SYSENTER and SYSEXIT instructions\n", query_cpu_feature(&info, Edx_1_Feature_Flags::sep) ? "yes" : "no ");
|
||||||
|
printf("mtrr: %s // Memory Type Range Registers\n", query_cpu_feature(&info, Edx_1_Feature_Flags::mtrr) ? "yes" : "no ");
|
||||||
|
printf("pge: %s // Page Global Enable bit in CR4\n", query_cpu_feature(&info, Edx_1_Feature_Flags::pge) ? "yes" : "no ");
|
||||||
|
printf("mca: %s // Machine check architecture\n", query_cpu_feature(&info, Edx_1_Feature_Flags::mca) ? "yes" : "no ");
|
||||||
|
printf("cmov: %s // Conditional move and FCMOV instructions\n", query_cpu_feature(&info, Edx_1_Feature_Flags::cmov) ? "yes" : "no ");
|
||||||
|
printf("pat: %s // Page Attribute Table\n", query_cpu_feature(&info, Edx_1_Feature_Flags::pat) ? "yes" : "no ");
|
||||||
|
printf("pse_36: %s // 36-bit page size extension\n", query_cpu_feature(&info, Edx_1_Feature_Flags::pse_36) ? "yes" : "no ");
|
||||||
|
printf("psn: %s // Processor Serial Number\n", query_cpu_feature(&info, Edx_1_Feature_Flags::psn) ? "yes" : "no ");
|
||||||
|
printf("clfsh: %s // CLFLUSH instruction (SSE2)\n", query_cpu_feature(&info, Edx_1_Feature_Flags::clfsh) ? "yes" : "no ");
|
||||||
|
printf("_resv2: %s // (reserved)\n", query_cpu_feature(&info, Edx_1_Feature_Flags::_resv2) ? "yes" : "no ");
|
||||||
|
printf("ds: %s // Debug store: save trace of executed jumps\n", query_cpu_feature(&info, Edx_1_Feature_Flags::ds) ? "yes" : "no ");
|
||||||
|
printf("acpi: %s // Onboard thermal control MSRs for ACPI\n", query_cpu_feature(&info, Edx_1_Feature_Flags::acpi) ? "yes" : "no ");
|
||||||
|
printf("mmx: %s // MMX instructions\n", query_cpu_feature(&info, Edx_1_Feature_Flags::mmx) ? "yes" : "no ");
|
||||||
|
printf("fxsr: %s // FXSAVE, FXRESTOR instructions, CR4 bit 9\n", query_cpu_feature(&info, Edx_1_Feature_Flags::fxsr) ? "yes" : "no ");
|
||||||
|
printf("sse: %s // SSE instructions (a.k.a. Katmai New Instructions)\n", query_cpu_feature(&info, Edx_1_Feature_Flags::sse) ? "yes" : "no ");
|
||||||
|
printf("sse2: %s // SSE2 instructions\n", query_cpu_feature(&info, Edx_1_Feature_Flags::sse2) ? "yes" : "no ");
|
||||||
|
printf("ss: %s // CPU cache implements self-snoop\n", query_cpu_feature(&info, Edx_1_Feature_Flags::ss) ? "yes" : "no ");
|
||||||
|
printf("htt: %s // Hyper-threading\n", query_cpu_feature(&info, Edx_1_Feature_Flags::htt) ? "yes" : "no ");
|
||||||
|
printf("tm: %s // Thermal monitor automatically limits temperature\n", query_cpu_feature(&info, Edx_1_Feature_Flags::tm) ? "yes" : "no ");
|
||||||
|
printf("ia64: %s // IA64 processor emulating x86\n", query_cpu_feature(&info, Edx_1_Feature_Flags::ia64) ? "yes" : "no ");
|
||||||
|
printf("pbe: %s // Pending Break Enable (PBE# pin) wakeup capability\n", query_cpu_feature(&info, Edx_1_Feature_Flags::pbe) ? "yes" : "no ");
|
||||||
|
printf("-------------------\n");
|
||||||
|
printf("Ecx_1_Feature_Flags\n");
|
||||||
|
printf("-------------------\n");
|
||||||
|
printf("sse3: %s // Prescott New Instructions-SSE3 (PNI)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::sse3) ? "yes" : "no ");
|
||||||
|
printf("pclmulqdq: %s // PCLMULQDQ\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::pclmulqdq) ? "yes" : "no ");
|
||||||
|
printf("dtes64: %s // 64-bit debug store (edx bit 21)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::dtes64) ? "yes" : "no ");
|
||||||
|
printf("monitor: %s // MONITOR and MWAIT instructions (SSE3)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::monitor) ? "yes" : "no ");
|
||||||
|
printf("ds_cpl: %s // CPL qualified debug store\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::ds_cpl) ? "yes" : "no ");
|
||||||
|
printf("vmx: %s // Virtual Machine eXtensions\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::vmx) ? "yes" : "no ");
|
||||||
|
printf("smx: %s // Safer Mode Extensions (LaGrande)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::smx) ? "yes" : "no ");
|
||||||
|
printf("est: %s // Enhanced SpeedStep\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::est) ? "yes" : "no ");
|
||||||
|
printf("tm2: %s // Thermal Monitor 2\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::tm2) ? "yes" : "no ");
|
||||||
|
printf("ssse3: %s // Supplemental SSE3 instructions\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::ssse3) ? "yes" : "no ");
|
||||||
|
printf("cnxt_id: %s // L1 Context ID\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::cnxt_id) ? "yes" : "no ");
|
||||||
|
printf("sdbg: %s // Silicon Debug interface\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::sdbg) ? "yes" : "no ");
|
||||||
|
printf("fma: %s // Fused multiply-add (FMA3)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::fma) ? "yes" : "no ");
|
||||||
|
printf("cx16: %s // CMPXCHG16B instruction\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::cx16) ? "yes" : "no ");
|
||||||
|
printf("xtpr: %s // Can disable sending task priority messages\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::xtpr) ? "yes" : "no ");
|
||||||
|
printf("pdcm: %s // Perfmon & debug capability\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::pdcm) ? "yes" : "no ");
|
||||||
|
printf("_resv1: %s // (reserved)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::_resv1) ? "yes" : "no ");
|
||||||
|
printf("pcid: %s // Process context identifiers (CR4 bit 17)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::pcid) ? "yes" : "no ");
|
||||||
|
printf("dca: %s // Direct cache access for DMA writes\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::dca) ? "yes" : "no ");
|
||||||
|
printf("sse4_1: %s // SSE4.1 instructions\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::sse4_1) ? "yes" : "no ");
|
||||||
|
printf("sse4_2: %s // SSE4.2 instructions\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::sse4_2) ? "yes" : "no ");
|
||||||
|
printf("x2apic: %s // x2APIC\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::x2apic) ? "yes" : "no ");
|
||||||
|
printf("movbe: %s // MOVBE instruction (big-endian)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::movbe) ? "yes" : "no ");
|
||||||
|
printf("popcnt: %s // POPCNT instruction\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::popcnt) ? "yes" : "no ");
|
||||||
|
printf("tsc_deadline: %s // APIC implements one-shot operation using a TSC deadline value\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::tsc_deadline) ? "yes" : "no ");
|
||||||
|
printf("aes: %s // AES instruction set\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::aes) ? "yes" : "no ");
|
||||||
|
printf("xsave: %s // XSAVE, XRESTOR, XSETBV, XGETBV\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::xsave) ? "yes" : "no ");
|
||||||
|
printf("osxsave: %s // XSAVE enabled by OS\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::osxsave) ? "yes" : "no ");
|
||||||
|
printf("avx: %s // Advanced Vector Extensions\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::avx) ? "yes" : "no ");
|
||||||
|
printf("f16c: %s // F16C (half-precision) FP feature\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::f16c) ? "yes" : "no ");
|
||||||
|
printf("rdrnd: %s // RDRAND (on-chip random number generator) feature\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::rdrnd) ? "yes" : "no ");
|
||||||
|
printf("hypervisor: %s // Hypervisor present (always zero on physical CPUs)\n", query_cpu_feature(&info, Ecx_1_Feature_Flags::hypervisor) ? "yes" : "no ");
|
||||||
|
printf("----------------------------\n");
|
||||||
|
printf("Ebx_7_Extended_Feature_Flags\n");
|
||||||
|
printf("----------------------------\n");
|
||||||
|
printf("fsgsbase: %s // Access to base of %%fs and %%gs\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::fsgsbase) ? "yes" : "no ");
|
||||||
|
printf("_idk1: %s //\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::_idk1) ? "yes" : "no ");
|
||||||
|
printf("sgx: %s // Software Guard Extensions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::sgx) ? "yes" : "no ");
|
||||||
|
printf("bmi1: %s // Bit Manipulation Instruction Set 1\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::bmi1) ? "yes" : "no ");
|
||||||
|
printf("hle: %s // TSX Hardware Lock Elision\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::hle) ? "yes" : "no ");
|
||||||
|
printf("avx2: %s // Advanced Vector Extensions 2\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx2) ? "yes" : "no ");
|
||||||
|
printf("_idk2: %s //\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::_idk2) ? "yes" : "no ");
|
||||||
|
printf("smep: %s // Supervisor Mode Execution Prevention\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::smep) ? "yes" : "no ");
|
||||||
|
printf("bmi2: %s // Bit Manipulation Instruction Set 2\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::bmi2) ? "yes" : "no ");
|
||||||
|
printf("erms: %s // Enhanced REP MOVSB/STOSB\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::erms) ? "yes" : "no ");
|
||||||
|
printf("invpcid: %s // INVPCID instruction\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::invpcid) ? "yes" : "no ");
|
||||||
|
printf("rtm: %s // TSX Restricted Transactional Memory\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::rtm) ? "yes" : "no ");
|
||||||
|
printf("pqm: %s // Platform Quality of Service Monitoring\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::pqm) ? "yes" : "no ");
|
||||||
|
printf("_idk3: %s //\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::_idk3) ? "yes" : "no ");
|
||||||
|
printf("mpx: %s // Intel MPX (Memory Protection Extensions)\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::mpx) ? "yes" : "no ");
|
||||||
|
printf("pqe: %s // Platform Quality of Service Enforcement\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::pqe) ? "yes" : "no ");
|
||||||
|
printf("avx512_f: %s // AVX-512 Foundation\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx512_f) ? "yes" : "no ");
|
||||||
|
printf("avx512_dq: %s // AVX-512 Doubleword and Quadword Instructions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx512_dq) ? "yes" : "no ");
|
||||||
|
printf("rdseed: %s // RDSEED instruction\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::rdseed) ? "yes" : "no ");
|
||||||
|
printf("adx: %s // Intel ADX (Multi-Precision Add-Carry Instruction Extensions)\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::adx) ? "yes" : "no ");
|
||||||
|
printf("smap: %s // Supervisor Mode Access Prevention\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::smap) ? "yes" : "no ");
|
||||||
|
printf("avx512_ifma: %s // AVX-512 Integer Fused Multiply-Add Instructions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx512_ifma) ? "yes" : "no ");
|
||||||
|
printf("pcommit: %s // PCOMMIT instruction\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::pcommit) ? "yes" : "no ");
|
||||||
|
printf("clflushopt: %s // CLFLUSHOPT instruction\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::clflushopt) ? "yes" : "no ");
|
||||||
|
printf("clwb: %s // CLWB instruction\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::clwb) ? "yes" : "no ");
|
||||||
|
printf("intel_pt: %s // Intel Processor Trace\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::intel_pt) ? "yes" : "no ");
|
||||||
|
printf("avx512_pf: %s // AVX-512 Prefetch Instructions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx512_pf) ? "yes" : "no ");
|
||||||
|
printf("avx512_er: %s // AVX-512 Exponential and Reciprocal Instructions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx512_er) ? "yes" : "no ");
|
||||||
|
printf("avx512_cd: %s // AVX-512 Conflict Detection Instructions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx512_cd) ? "yes" : "no ");
|
||||||
|
printf("sha: %s // Intel SHA extensions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::sha) ? "yes" : "no ");
|
||||||
|
printf("avx512_bw: %s // AVX-512 Byte and Word Instructions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx512_bw) ? "yes" : "no ");
|
||||||
|
printf("avx512_vl: %s // AVX-512 Vector Length Extensions\n", query_cpu_feature(&info, Ebx_7_Extended_Feature_Flags::avx512_vl) ? "yes" : "no ");
|
||||||
|
printf("----------------------------\n");
|
||||||
|
printf("Ecx_7_Extended_Feature_Flags\n");
|
||||||
|
printf("----------------------------\n");
|
||||||
|
printf("prefetchwt1: %s // PREFETCHWT1 instruction\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::prefetchwt1) ? "yes" : "no ");
|
||||||
|
printf("avx512_vbmi: %s // AVX-512 Vector Bit Manipulation Instructions\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::avx512_vbmi) ? "yes" : "no ");
|
||||||
|
printf("umip: %s // User-mode Instruction Prevention\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::umip) ? "yes" : "no ");
|
||||||
|
printf("pku: %s // Memory Protection Keys for User-mode pages\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::pku) ? "yes" : "no ");
|
||||||
|
printf("ospke: %s // PKU enabled by OS\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::ospke) ? "yes" : "no ");
|
||||||
|
printf("waitpkg: %s // Timed pause and user-level monitor/wait\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::waitpkg) ? "yes" : "no ");
|
||||||
|
printf("avx512_vbmi2: %s // AVX-512 Vector Bit Manipulation Instructions 2\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::avx512_vbmi2) ? "yes" : "no ");
|
||||||
|
printf("cet_ss: %s // Control flow enforcement (CET) shadow stack\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::cet_ss) ? "yes" : "no ");
|
||||||
|
printf("gfni: %s // Galois Field instructions\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::gfni) ? "yes" : "no ");
|
||||||
|
printf("vaes: %s // Vector AES instruction set (VEX-256/EVEX)\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::vaes) ? "yes" : "no ");
|
||||||
|
printf("vpclmulqdq: %s // CLMUL instruction set (VEX-256/EVEX)\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::vpclmulqdq) ? "yes" : "no ");
|
||||||
|
printf("avx512_vnni: %s // AVX-512 Vector Neural Network Instructions\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::avx512_vnni) ? "yes" : "no ");
|
||||||
|
printf("avx512_bitalg: %s // AVX-512 BITALG instructions\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::avx512_bitalg) ? "yes" : "no ");
|
||||||
|
printf("_resv1: %s // (reserved)\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::_resv1) ? "yes" : "no ");
|
||||||
|
printf("avx512_vpopcntdq: %s // AVX-512 Vector Population Count Double and Quad-word\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::avx512_vpopcntdq)? "yes" : "no ");
|
||||||
|
printf("_resv2: %s // (reserved)\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::_resv2) ? "yes" : "no ");
|
||||||
|
printf("intel_5lp: %s // 5-level paging\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::intel_5lp) ? "yes" : "no ");
|
||||||
|
printf("mawau1: %s // The value of userspace MPX Address-Width Adjust used ...\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::mawau1) ? "yes" : "no ");
|
||||||
|
printf("mawau2: %s // ... by the BNDLDX and BNDSTX Intel MPX instructions ...\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::mawau2) ? "yes" : "no ");
|
||||||
|
printf("mawau3: %s // ... in 64-bit mode\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::mawau3) ? "yes" : "no ");
|
||||||
|
printf("mawau4: %s //\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::mawau4) ? "yes" : "no ");
|
||||||
|
printf("mawau5: %s //\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::mawau5) ? "yes" : "no ");
|
||||||
|
printf("rdpid: %s // Read Processor ID and IA32_TSC_AUX\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::rdpid) ? "yes" : "no ");
|
||||||
|
printf("_resv3: %s // (reserved)\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::_resv3) ? "yes" : "no ");
|
||||||
|
printf("_resv4: %s // (reserved)\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::_resv4) ? "yes" : "no ");
|
||||||
|
printf("cldemote: %s // Cache line demote\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::cldemote) ? "yes" : "no ");
|
||||||
|
printf("_resv5: %s // (reserved)\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::_resv5) ? "yes" : "no ");
|
||||||
|
printf("movdiri: %s //\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::movdiri) ? "yes" : "no ");
|
||||||
|
printf("movdir64b: %s //\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::movdir64b) ? "yes" : "no ");
|
||||||
|
printf("enqcmd: %s // Enqueue Stores\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::enqcmd) ? "yes" : "no ");
|
||||||
|
printf("sgx_lc: %s // SGX Launch Configuration\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::sgx_lc) ? "yes" : "no ");
|
||||||
|
printf("pks: %s // Protection keys for supervisor-mode pages\n", query_cpu_feature(&info, Ecx_7_Extended_Feature_Flags::pks) ? "yes" : "no ");
|
||||||
|
printf("----------------------------\n");
|
||||||
|
printf("Edx_7_Extended_Feature_Flags\n");
|
||||||
|
printf("----------------------------\n");
|
||||||
|
printf("_resv1: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv1) ? "yes" : "no ");
|
||||||
|
printf("_resv2: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv2) ? "yes" : "no ");
|
||||||
|
printf("avx512_4vnniw: %s // AVX-512 4-register Neural Network Instructions\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::avx512_4vnniw) ? "yes" : "no ");
|
||||||
|
printf("avx512_4fmaps: %s // AVX-512 4-register Multiply Accumulation Single precision\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::avx512_4fmaps) ? "yes" : "no ");
|
||||||
|
printf("fsrm: %s // Fast Short REP MOVSB\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::fsrm) ? "yes" : "no ");
|
||||||
|
printf("_resv3: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv3) ? "yes" : "no ");
|
||||||
|
printf("_resv4: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv4) ? "yes" : "no ");
|
||||||
|
printf("_resv5: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv5) ? "yes" : "no ");
|
||||||
|
printf("avx512_vp2intersect: %s // AVX-512 VP2INTERSECT Doubleword and Quadword Instructions\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::avx512_vp2intersect) ? "yes" : "no ");
|
||||||
|
printf("SRBDS_CTRL: %s // Special Register Buffer Data Sampling Mitigations\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::SRBDS_CTRL) ? "yes" : "no ");
|
||||||
|
printf("md_clear: %s // VERW instruction clears CPU buffers\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::md_clear) ? "yes" : "no ");
|
||||||
|
printf("_resv6: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv6) ? "yes" : "no ");
|
||||||
|
printf("_resv7: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv7) ? "yes" : "no ");
|
||||||
|
printf("tsx_force_abort: %s //\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::tsx_force_abort) ? "yes" : "no ");
|
||||||
|
printf("serialize: %s // Serialize instruction execution\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::serialize) ? "yes" : "no ");
|
||||||
|
printf("hybrid: %s //\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::hybrid) ? "yes" : "no ");
|
||||||
|
printf("TSXLDTRK: %s // TSX suspend load address tracking\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::TSXLDTRK) ? "yes" : "no ");
|
||||||
|
printf("_resv8: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv8) ? "yes" : "no ");
|
||||||
|
printf("pconfig: %s // Platform configuration (Memory Encryption Technologies Instructions)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::pconfig) ? "yes" : "no ");
|
||||||
|
printf("lbr: %s // Architectural Last Branch Records\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::lbr) ? "yes" : "no ");
|
||||||
|
printf("cet_ibt: %s // Control flow enforcement (CET) indirect branch tracking\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::cet_ibt) ? "yes" : "no ");
|
||||||
|
printf("_resv9: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv9) ? "yes" : "no ");
|
||||||
|
printf("amx_bf16: %s // Tile computation on bfloat16 numbers\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::amx_bf16) ? "yes" : "no ");
|
||||||
|
printf("_resv10: %s // (reserved)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::_resv10) ? "yes" : "no ");
|
||||||
|
printf("amx_tile: %s // Tile architecture\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::amx_tile) ? "yes" : "no ");
|
||||||
|
printf("amx_int8: %s // Tile computation on 8-bit integers\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::amx_int8) ? "yes" : "no ");
|
||||||
|
printf("spec_ctrl: %s // Speculation Control, part of Indirect Branch Control (IBC): Indirect Branch Restricted Speculation (IBRS) and Indirect Branch Prediction Barrier (IBPB)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::spec_ctrl) ? "yes" : "no ");
|
||||||
|
printf("stibp: %s // Single Thread Indirect Branch Predictor, part of IBC\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::stibp) ? "yes" : "no ");
|
||||||
|
printf("l1d_flush: %s // IA32_FLUSH_CMD MSR\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::l1d_flush) ? "yes" : "no ");
|
||||||
|
printf("ia32_arch_capabilities: %s // Speculative Side Channel Mitigations\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::ia32_arch_capabilities) ? "yes" : "no ");
|
||||||
|
printf("ia32_core_capabilities: %s // Support for a MSR listing model-specific core capabilities\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::ia32_core_capabilities) ? "yes" : "no ");
|
||||||
|
printf("ssbd: %s // Speculative Store Bypass Disable, as mitigation for Speculative Store Bypass (IA32_SPEC_CTRL)\n", query_cpu_feature(&info, Edx_7_Extended_Feature_Flags::ssbd) ? "yes" : "no ");
|
||||||
|
printf("-----------------------------\n");
|
||||||
|
printf("Ebx_81_Extended_Feature_Flags\n");
|
||||||
|
printf("-----------------------------\n");
|
||||||
|
printf("syscall: %s // SYSCALL and SYSRET instructions\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::syscall) ? "yes" : "no ");
|
||||||
|
printf("mp: %s // Multiprocessor Capable\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::mp) ? "yes" : "no ");
|
||||||
|
printf("nx: %s // NX (no-execute) bit\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::nx) ? "yes" : "no ");
|
||||||
|
printf("mmxext: %s // Extended MMX\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::mmxext) ? "yes" : "no ");
|
||||||
|
printf("fxsr_opt: %s // FXSAVE/FXRSTOR optimizations\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::fxsr_opt) ? "yes" : "no ");
|
||||||
|
printf("pdpe1gb: %s // Gibibyte pages\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::pdpe1gb) ? "yes" : "no ");
|
||||||
|
printf("rdtscp: %s // RDTSCP instruction\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::rdtscp) ? "yes" : "no ");
|
||||||
|
printf("l1d_flush: %s // IA32_FLUSH_CMD MSR\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::l1d_flush) ? "yes" : "no ");
|
||||||
|
printf("lm: %s // Long mode\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::lm) ? "yes" : "no ");
|
||||||
|
printf("_3dnowext: %s // Extended 3DNow!\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::_3dnowext) ? "yes" : "no ");
|
||||||
|
printf("_3dnow: %s // 3DNow!\n", query_cpu_feature(&info, Edx_81_Extended_Feature_Flags::_3dnow) ? "yes" : "no ");
|
||||||
|
printf("-----------------------------\n");
|
||||||
|
printf("Ecx_81_Extended_Feature_Flags\n");
|
||||||
|
printf("-----------------------------\n");
|
||||||
|
printf("lahf_lm: %s // LAHF/SAHF in long mode\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::lahf_lm) ? "yes" : "no ");
|
||||||
|
printf("cmp_legacy: %s // Hyperthreading not valid\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::cmp_legacy) ? "yes" : "no ");
|
||||||
|
printf("svm: %s // Secure Virtual Machine\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::svm) ? "yes" : "no ");
|
||||||
|
printf("extapic: %s // Extended APIC space\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::extapic) ? "yes" : "no ");
|
||||||
|
printf("cr8_legacy: %s // CR8 in 32-bit mode\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::cr8_legacy) ? "yes" : "no ");
|
||||||
|
printf("abm: %s // Advanced bit manipulation (lzcnt and popcnt)\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::abm) ? "yes" : "no ");
|
||||||
|
printf("sse4a: %s // SSE4a\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::sse4a) ? "yes" : "no ");
|
||||||
|
printf("misalignsse: %s // Misaligned SSE mode\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::misalignsse) ? "yes" : "no ");
|
||||||
|
printf("_3dnowprefetch: %s // PREFETCH and PREFETCHW instructions\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::_3dnowprefetch) ? "yes" : "no ");
|
||||||
|
printf("osvw: %s // OS Visible Workaround\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::osvw) ? "yes" : "no ");
|
||||||
|
printf("ibs: %s // Instruction Based Sampling\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::ibs) ? "yes" : "no ");
|
||||||
|
printf("xop: %s // XOP instruction set\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::xop) ? "yes" : "no ");
|
||||||
|
printf("skinit: %s // SKINIT/STGI instructions\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::skinit) ? "yes" : "no ");
|
||||||
|
printf("wdt: %s // Watchdog timer\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::wdt) ? "yes" : "no ");
|
||||||
|
printf("_resv1: %s // (reserved)\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::_resv1) ? "yes" : "no ");
|
||||||
|
printf("lwp: %s // Light Weight Profiling\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::lwp) ? "yes" : "no ");
|
||||||
|
printf("fma4: %s // 4 operands fused multiply-add\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::fma4) ? "yes" : "no ");
|
||||||
|
printf("tce: %s // Translation Cache Extension\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::tce) ? "yes" : "no ");
|
||||||
|
printf("_resv2: %s // (reserved)\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::_resv2) ? "yes" : "no ");
|
||||||
|
printf("nodeid_msr: %s // NodeID MSR\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::nodeid_msr) ? "yes" : "no ");
|
||||||
|
printf("_resv3: %s // (reserved)\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::_resv3) ? "yes" : "no ");
|
||||||
|
printf("tbm: %s // Trailing Bit Manipulation\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::tbm) ? "yes" : "no ");
|
||||||
|
printf("topoext: %s // opology Extensions\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::topoext) ? "yes" : "no ");
|
||||||
|
printf("perfctr_core: %s // Core performance counter extensions\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::perfctr_core) ? "yes" : "no ");
|
||||||
|
printf("perfctr_nb: %s // NB performance counter extensions\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::perfctr_nb) ? "yes" : "no ");
|
||||||
|
printf("_resv4: %s // (reserved)\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::_resv4) ? "yes" : "no ");
|
||||||
|
printf("dbx: %s // Data breakpoint extensions\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::dbx) ? "yes" : "no ");
|
||||||
|
printf("perftsc: %s // Performance TSC\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::perftsc) ? "yes" : "no ");
|
||||||
|
printf("pcx_l2i: %s // L2I perf counter extensions\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::pcx_l2i) ? "yes" : "no ");
|
||||||
|
printf("_resv5: %s // (reserved)\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::_resv5) ? "yes" : "no ");
|
||||||
|
printf("_resv6: %s // (reserved)\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::_resv6) ? "yes" : "no ");
|
||||||
|
printf("_resv7: %s // (reserved)\n", query_cpu_feature(&info, Ecx_81_Extended_Feature_Flags::_resv7) ? "yes" : "no ");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print_full_cpu_info();
|
||||||
|
}
|
||||||
+715
@@ -0,0 +1,715 @@
|
|||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "../types.hpp"
|
||||||
|
|
||||||
|
u32 hm_hash(u32 u);
|
||||||
|
inline bool hm_objects_match(u32 a, u32 b);
|
||||||
|
struct Key;
|
||||||
|
u32 hm_hash(Key u);
|
||||||
|
inline bool hm_objects_match(Key a, Key b);
|
||||||
|
|
||||||
|
#define ZoneScoped
|
||||||
|
#define ZoneScopedN(name)
|
||||||
|
|
||||||
|
#define USE_FTB_MALLOC
|
||||||
|
#include "../print.hpp"
|
||||||
|
#include "../testing.hpp"
|
||||||
|
#include "../bucket_allocator.hpp"
|
||||||
|
#include "../error.hpp"
|
||||||
|
#include "../hooks.hpp"
|
||||||
|
#include "../hashmap.hpp"
|
||||||
|
#include "../stacktrace.hpp"
|
||||||
|
#include "../scheduler.cpp"
|
||||||
|
|
||||||
|
#include "../error.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
u32 hm_hash(u32 u) {
|
||||||
|
return ((u64)u * 2654435761) % 4294967296;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool hm_objects_match(u32 a, u32 b) {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Key {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int z;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
u32 hm_hash(Key u) {
|
||||||
|
return ((u.y ^ (u.x << 1)) >> 1) ^ u.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool hm_objects_match(Key a, Key b) {
|
||||||
|
return a.x == b.x
|
||||||
|
&& a.y == b.y
|
||||||
|
&& a.z == b.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto print_dots(FILE* f) -> u32 {
|
||||||
|
return print_to_file(f, "...");
|
||||||
|
}
|
||||||
|
|
||||||
|
proc is_sorted = [](Array_List<s32> list) -> bool {
|
||||||
|
for (u32 i = 0; i < list.count - 1; ++i) {
|
||||||
|
if (list.data[i] > list.data[i+1])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
proc is_sorted_vp = [](Array_List<void*> list) -> bool {
|
||||||
|
for (u32 i = 0; i < list.count - 1; ++i) {
|
||||||
|
if (list.data[i] > list.data[i+1])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
auto test_printer() -> void {
|
||||||
|
u32 arr[] = {1,2,3,4,1,1,3};
|
||||||
|
f32 f_arr[] = {1.1,2.1,3.2};
|
||||||
|
|
||||||
|
|
||||||
|
register_printer("dots", print_dots, Printer_Function_Type::_void);
|
||||||
|
|
||||||
|
u32 u1 = -1;
|
||||||
|
u64 u2 = -1;
|
||||||
|
|
||||||
|
char* str;
|
||||||
|
print_to_string(&str, " - %{dots[5]} %{->} <> %{->,2}\n", &u1, &arr, nullptr);
|
||||||
|
print("---> %{->char}", str);
|
||||||
|
|
||||||
|
print(" - %{dots[3]}\n");
|
||||||
|
print(" - %{u32} %{u64}\n", u1, u2);
|
||||||
|
print(" - %{u32} %{u32} %{u32}\n", 2, 5, 7);
|
||||||
|
print(" - %{f32} %{f32} %{f32}\n", 2.0, 5.0, 7.0);
|
||||||
|
print(" - %{u32} %{bool} %{->char}\n", 2, true, "hello");
|
||||||
|
print(" - %{f32[3]}\n", f_arr);
|
||||||
|
print(" - %{f32,3}\n", 44.9, 55.1, 66.2);
|
||||||
|
print(" - %{u32[5]}\n", arr);
|
||||||
|
print(" - %{u32[*]}\n", arr, 4);
|
||||||
|
print(" - %{u32,5}\n", 1,2,3,4,1,2);
|
||||||
|
print(" - %{unknown%d}\n", 1);
|
||||||
|
print(" - %{s32,3}\n", -1,200,-300);
|
||||||
|
print(" - %{->} <> %{->,2}\n", &u1, &arr, nullptr);
|
||||||
|
|
||||||
|
print("%{->char}%{->char}%{->char}",
|
||||||
|
true ? "general " : "",
|
||||||
|
false ? "validation " : "",
|
||||||
|
false ? "performance " : "");
|
||||||
|
|
||||||
|
// print("%{->char}%{->char}\n\n", "hallo","");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
auto test_hm() -> void {
|
||||||
|
Hash_Map<u32, u32> h1;
|
||||||
|
h1.alloc();
|
||||||
|
defer { h1.dealloc(); };
|
||||||
|
|
||||||
|
h1.set_object(1, 2);
|
||||||
|
h1.set_object(2, 4);
|
||||||
|
h1.set_object(3, 6);
|
||||||
|
h1.set_object(4, 8);
|
||||||
|
|
||||||
|
assert(h1.key_exists(1), "key shoud exist");
|
||||||
|
assert(h1.key_exists(2), "key shoud exist");
|
||||||
|
assert(h1.key_exists(3), "key shoud exist");
|
||||||
|
assert(h1.key_exists(4), "key shoud exist");
|
||||||
|
assert(!h1.key_exists(5), "key shoud not exist");
|
||||||
|
|
||||||
|
assert(h1.get_object(1) == 2, "value should be correct");
|
||||||
|
assert(h1.get_object(2) == 4, "value should be correct");
|
||||||
|
assert(h1.get_object(3) == 6, "value should be correct");
|
||||||
|
assert(h1.get_object(4) == 8, "value should be correct");
|
||||||
|
|
||||||
|
|
||||||
|
Hash_Map<Key, u32> h2;
|
||||||
|
h2.alloc();
|
||||||
|
defer { h2.dealloc(); };
|
||||||
|
|
||||||
|
h2.set_object({.x = 1, .y = 2, .z = 3}, 1);
|
||||||
|
h2.set_object({.x = 3, .y = 3, .z = 3}, 3);
|
||||||
|
|
||||||
|
assert(h2.key_exists({.x = 1, .y = 2, .z = 3}), "key shoud exist");
|
||||||
|
assert(h2.key_exists({.x = 3, .y = 3, .z = 3}), "key shoud exist");
|
||||||
|
|
||||||
|
assert(h2.get_object({.x = 1, .y = 2, .z = 3}) == 1, "value should be correct");
|
||||||
|
assert(h2.get_object({.x = 3, .y = 3, .z = 3}) == 3, "value should be correct");
|
||||||
|
|
||||||
|
h2.for_each([] (Key k, u32 v, u32 i) {
|
||||||
|
print("%{s32} %{u32} %{u32}\n", k.x, v, i);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_stack_array_lists() -> testresult {
|
||||||
|
Stack_Array_List<int> list(20);
|
||||||
|
|
||||||
|
assert_equal_int(list.count, 0);
|
||||||
|
assert_equal_int(list.length, 20);
|
||||||
|
assert(list.data != NULL, "list should have some data allocated");
|
||||||
|
|
||||||
|
// test sum of empty list
|
||||||
|
int sum = 0;
|
||||||
|
int iter = 0;
|
||||||
|
for (auto e : list) {
|
||||||
|
sum += e;
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
assert_equal_int(sum, 0);
|
||||||
|
assert_equal_int(iter, 0);
|
||||||
|
|
||||||
|
// append some elements
|
||||||
|
list.append(1);
|
||||||
|
list.append(2);
|
||||||
|
list.append(3);
|
||||||
|
list.append(4);
|
||||||
|
|
||||||
|
assert_equal_int(list.count, 4);
|
||||||
|
assert_equal_int(list.length, 20);
|
||||||
|
|
||||||
|
// test sum again
|
||||||
|
sum = 0;
|
||||||
|
iter = 0;
|
||||||
|
for (auto e : list) {
|
||||||
|
sum += e;
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal_int(sum, 10);
|
||||||
|
assert_equal_int(iter, 4);
|
||||||
|
|
||||||
|
// bracketed access
|
||||||
|
list[0] = 11;
|
||||||
|
list[1] = 3;
|
||||||
|
list[2] = 2;
|
||||||
|
list.append(5);
|
||||||
|
|
||||||
|
// test sum again
|
||||||
|
sum = 0;
|
||||||
|
iter = 0;
|
||||||
|
for (auto e : list) {
|
||||||
|
sum += e;
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
assert_equal_int(sum, 25);
|
||||||
|
assert_equal_int(iter, 5);
|
||||||
|
|
||||||
|
// assert memory correct
|
||||||
|
assert_equal_int(list.data[0], 11);
|
||||||
|
assert_equal_int(list.data[1], 3);
|
||||||
|
assert_equal_int(list.data[2], 2);
|
||||||
|
assert_equal_int(list.data[3], 4);
|
||||||
|
assert_equal_int(list.data[4], 5);
|
||||||
|
|
||||||
|
// removing some indices
|
||||||
|
list.remove_index(4);
|
||||||
|
|
||||||
|
// test sum again
|
||||||
|
sum = 0;
|
||||||
|
iter = 0;
|
||||||
|
for (auto e : list) {
|
||||||
|
sum += e;
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
assert_equal_int(sum, 20);
|
||||||
|
assert_equal_int(iter, 4);
|
||||||
|
|
||||||
|
// removing some indices
|
||||||
|
list.remove_index(1);
|
||||||
|
list.remove_index(0);
|
||||||
|
|
||||||
|
// test sum again
|
||||||
|
sum = 0;
|
||||||
|
iter = 0;
|
||||||
|
for (auto e : list) {
|
||||||
|
sum += e;
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal_int(sum, 6);
|
||||||
|
assert_equal_int(iter, 2);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_queue() -> testresult {
|
||||||
|
Queue<int> q;
|
||||||
|
q.alloc(4);
|
||||||
|
defer {
|
||||||
|
q.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(q.is_empty(), "queue should start empty");
|
||||||
|
assert_equal_int(q.get_count(), 0);
|
||||||
|
|
||||||
|
q.push_back(1);
|
||||||
|
q.push_back(2);
|
||||||
|
q.push_back(3);
|
||||||
|
|
||||||
|
assert_equal_int(q.get_count(), 3);
|
||||||
|
|
||||||
|
assert_equal_int(q.get_next(), 1);
|
||||||
|
assert_equal_int(q.get_count(), 2);
|
||||||
|
assert(!q.is_empty(), "should not be empty");
|
||||||
|
|
||||||
|
assert_equal_int(q.get_next(), 2);
|
||||||
|
assert_equal_int(q.get_count(), 1);
|
||||||
|
q.push_back(4);
|
||||||
|
assert_equal_int(q.get_count(), 2);
|
||||||
|
|
||||||
|
assert_equal_int(q.get_next(), 3);
|
||||||
|
assert_equal_int(q.get_count(), 1);
|
||||||
|
assert(!q.is_empty(), "should not be empty");
|
||||||
|
|
||||||
|
assert_equal_int(q.get_next(), 4);
|
||||||
|
assert(q.is_empty(), "should be empty");
|
||||||
|
assert_equal_int(q.get_count(), 0);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_array_lists_adding_and_removing() -> testresult {
|
||||||
|
// test adding and removing
|
||||||
|
Array_List<s32> list;
|
||||||
|
list.alloc();
|
||||||
|
|
||||||
|
defer {
|
||||||
|
list.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
list.append(1);
|
||||||
|
list.append(2);
|
||||||
|
list.append(3);
|
||||||
|
list.append(4);
|
||||||
|
|
||||||
|
assert_equal_int(list.count, 4);
|
||||||
|
|
||||||
|
list.remove_index(0);
|
||||||
|
|
||||||
|
assert_equal_int(list.count, 3);
|
||||||
|
assert_equal_int(list[0], 4);
|
||||||
|
assert_equal_int(list[1], 2);
|
||||||
|
assert_equal_int(list[2], 3);
|
||||||
|
|
||||||
|
list.remove_index(2);
|
||||||
|
|
||||||
|
assert_equal_int(list.count, 2);
|
||||||
|
assert_equal_int(list[0], 4);
|
||||||
|
assert_equal_int(list[1], 2);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
proc test_array_lists_sorting() -> testresult {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Test simple numbers
|
||||||
|
//
|
||||||
|
//
|
||||||
|
Array_List<s32> list;
|
||||||
|
list.alloc();
|
||||||
|
defer {
|
||||||
|
list.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
list.append(1);
|
||||||
|
list.append(2);
|
||||||
|
list.append(3);
|
||||||
|
list.append(4);
|
||||||
|
|
||||||
|
list.sort();
|
||||||
|
assert_equal_int(is_sorted(list), true);
|
||||||
|
|
||||||
|
list.append(4);
|
||||||
|
list.append(2);
|
||||||
|
list.append(1);
|
||||||
|
|
||||||
|
assert_equal_int(is_sorted(list), false);
|
||||||
|
list.sort();
|
||||||
|
assert_equal_int(is_sorted(list), true);
|
||||||
|
|
||||||
|
list.clear();
|
||||||
|
list.extend({
|
||||||
|
8023, 7529, 2392, 7110,
|
||||||
|
3259, 2484, 9695, 2199,
|
||||||
|
6729, 9009, 8429, 7208});
|
||||||
|
assert_equal_int(is_sorted(list), false);
|
||||||
|
list.sort();
|
||||||
|
assert_equal_int(is_sorted(list), true);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Test adding and removing
|
||||||
|
//
|
||||||
|
//
|
||||||
|
Array_List<s32> list1;
|
||||||
|
list1.alloc();
|
||||||
|
defer {
|
||||||
|
list1.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
list1.append(1);
|
||||||
|
list1.append(2);
|
||||||
|
list1.append(3);
|
||||||
|
list1.append(4);
|
||||||
|
|
||||||
|
list1.sort();
|
||||||
|
|
||||||
|
assert_equal_int(list1.count, 4);
|
||||||
|
|
||||||
|
assert_equal_int(list1[0], 1);
|
||||||
|
assert_equal_int(list1[1], 2);
|
||||||
|
assert_equal_int(list1[2], 3);
|
||||||
|
assert_equal_int(list1[3], 4);
|
||||||
|
assert_equal_int(is_sorted(list1), true);
|
||||||
|
|
||||||
|
list1.append(0);
|
||||||
|
list1.append(5);
|
||||||
|
|
||||||
|
assert_equal_int(list1.count, 6);
|
||||||
|
|
||||||
|
list1.sort();
|
||||||
|
|
||||||
|
assert_equal_int(list1[0], 0);
|
||||||
|
assert_equal_int(list1[1], 1);
|
||||||
|
assert_equal_int(list1[2], 2);
|
||||||
|
assert_equal_int(list1[3], 3);
|
||||||
|
assert_equal_int(list1[4], 4);
|
||||||
|
assert_equal_int(list1[5], 5);
|
||||||
|
assert_equal_int(is_sorted(list1), true);
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// pointer list
|
||||||
|
Array_List<void*> al;
|
||||||
|
al.alloc();
|
||||||
|
defer {
|
||||||
|
al.dealloc();
|
||||||
|
};
|
||||||
|
al.append((void*)0x1703102F100);
|
||||||
|
al.append((void*)0x1703102F1D8);
|
||||||
|
al.append((void*)0x1703102F148);
|
||||||
|
al.append((void*)0x1703102F190);
|
||||||
|
al.append((void*)0x1703102F190);
|
||||||
|
al.append((void*)0x1703102F1D8);
|
||||||
|
|
||||||
|
assert_equal_int(is_sorted_vp(al), false);
|
||||||
|
al.sort();
|
||||||
|
assert_equal_int(is_sorted_vp(al), true);
|
||||||
|
|
||||||
|
assert_not_equal_int(al.sorted_find((void*)0x1703102F100), -1);
|
||||||
|
assert_not_equal_int(al.sorted_find((void*)0x1703102F1D8), -1);
|
||||||
|
assert_not_equal_int(al.sorted_find((void*)0x1703102F148), -1);
|
||||||
|
assert_not_equal_int(al.sorted_find((void*)0x1703102F190), -1);
|
||||||
|
assert_not_equal_int(al.sorted_find((void*)0x1703102F190), -1);
|
||||||
|
assert_not_equal_int(al.sorted_find((void*)0x1703102F1D8), -1);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_array_lists_searching() -> testresult {
|
||||||
|
Array_List<s32> list1;
|
||||||
|
list1.alloc();
|
||||||
|
defer {
|
||||||
|
list1.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
list1.append(1);
|
||||||
|
list1.append(2);
|
||||||
|
list1.append(3);
|
||||||
|
list1.append(4);
|
||||||
|
|
||||||
|
s32 index = list1.sorted_find(3);
|
||||||
|
assert_equal_int(index, 2);
|
||||||
|
|
||||||
|
index = list1.sorted_find(1);
|
||||||
|
assert_equal_int(index, 0);
|
||||||
|
|
||||||
|
index = list1.sorted_find(5);
|
||||||
|
assert_equal_int(index, -1);
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_bucket_allocator() -> testresult {
|
||||||
|
Bucket_Allocator<s32> ba;
|
||||||
|
ba.alloc();
|
||||||
|
defer {
|
||||||
|
ba.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
s32* s1 = ba.allocate();
|
||||||
|
s32* s2 = ba.allocate();
|
||||||
|
s32* s3 = ba.allocate();
|
||||||
|
s32* s4 = ba.allocate();
|
||||||
|
s32* s5 = ba.allocate();
|
||||||
|
|
||||||
|
*s1 = 1;
|
||||||
|
*s2 = 2;
|
||||||
|
*s3 = 3;
|
||||||
|
*s4 = 4;
|
||||||
|
*s5 = 5;
|
||||||
|
|
||||||
|
s32 wrong_answers = 0;
|
||||||
|
s32 counter = 1;
|
||||||
|
ba.for_each([&](s32* s) -> void {
|
||||||
|
if(counter != *s)
|
||||||
|
++wrong_answers;
|
||||||
|
++counter;
|
||||||
|
});
|
||||||
|
assert_equal_int(wrong_answers, 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bucket_Allocator<s32> ba2;
|
||||||
|
ba2.alloc();
|
||||||
|
defer {
|
||||||
|
ba2.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
s1 = ba2.allocate();
|
||||||
|
s2 = ba2.allocate();
|
||||||
|
s3 = ba2.allocate();
|
||||||
|
|
||||||
|
|
||||||
|
s32* s3_copy = ba2.allocate();
|
||||||
|
s32* s3_copy2 = ba2.allocate();
|
||||||
|
s32* s3_copy3 = ba2.allocate();
|
||||||
|
*s3_copy = 3;
|
||||||
|
ba2.free_object(s3_copy);
|
||||||
|
|
||||||
|
|
||||||
|
s4 = ba2.allocate();
|
||||||
|
|
||||||
|
ba2.free_object(s3_copy2);
|
||||||
|
|
||||||
|
s5 = ba2.allocate();
|
||||||
|
|
||||||
|
ba2.free_object(s3_copy3);
|
||||||
|
|
||||||
|
*s1 = 1;
|
||||||
|
*s2 = 2;
|
||||||
|
*s3 = 3;
|
||||||
|
*s4 = 4;
|
||||||
|
*s5 = 5;
|
||||||
|
|
||||||
|
wrong_answers = 0;
|
||||||
|
counter = 1;
|
||||||
|
ba2.for_each([&](s32* s) -> void {
|
||||||
|
if(counter != *s)
|
||||||
|
++wrong_answers;
|
||||||
|
++counter;
|
||||||
|
});
|
||||||
|
assert_equal_int(wrong_answers, 0);
|
||||||
|
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto test_array_list_sort_many() -> testresult {
|
||||||
|
Array_List<s32> list;
|
||||||
|
list.alloc();
|
||||||
|
defer {
|
||||||
|
list.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 10000; ++i) {
|
||||||
|
list.append(rand());
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal_int(is_sorted(list), false);
|
||||||
|
list.sort();
|
||||||
|
assert_equal_int(is_sorted(list), true);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10000; ++i) {
|
||||||
|
assert_not_equal_int(list.sorted_find(list.data[i]), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.clear();
|
||||||
|
for (int i = 0; i < 1111; ++i) {
|
||||||
|
list.append(rand());
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal_int(is_sorted(list), false);
|
||||||
|
list.sort();
|
||||||
|
assert_equal_int(is_sorted(list), true);
|
||||||
|
|
||||||
|
for (int i = 0; i < 1111; ++i) {
|
||||||
|
assert_not_equal_int(list.sorted_find(list.data[i]), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
list.clear();
|
||||||
|
for (int i = 0; i < 3331; ++i) {
|
||||||
|
list.append(rand());
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal_int(is_sorted(list), false);
|
||||||
|
list.sort();
|
||||||
|
assert_equal_int(is_sorted(list), true);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3331; ++i) {
|
||||||
|
assert_not_equal_int(list.sorted_find(list.data[i]), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto test_hooks() -> testresult {
|
||||||
|
s32 a = 0;
|
||||||
|
s32 b = 0;
|
||||||
|
s32 c = 0;
|
||||||
|
|
||||||
|
Hook hook;
|
||||||
|
hook << [&]() {
|
||||||
|
a = 1;
|
||||||
|
};
|
||||||
|
hook << [&]() {
|
||||||
|
// NOTE(Felix): assert correct execution order
|
||||||
|
if (a == 1 && c == 0) {
|
||||||
|
b = 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
hook << [&]() {
|
||||||
|
c = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_equal_int(a, 0);
|
||||||
|
assert_equal_int(b, 0);
|
||||||
|
assert_equal_int(c, 0);
|
||||||
|
|
||||||
|
hook();
|
||||||
|
|
||||||
|
assert_equal_int(a, 1);
|
||||||
|
assert_equal_int(b, 2);
|
||||||
|
assert_equal_int(c, 3);
|
||||||
|
|
||||||
|
a = 0;
|
||||||
|
b = 0;
|
||||||
|
c = 0;
|
||||||
|
|
||||||
|
// NOTE(Felix): hook should be empty now
|
||||||
|
hook();
|
||||||
|
|
||||||
|
assert_equal_int(a, 0);
|
||||||
|
assert_equal_int(b, 0);
|
||||||
|
assert_equal_int(c, 0);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto test_scheduler_animations() -> testresult {
|
||||||
|
using namespace Scheduler;
|
||||||
|
|
||||||
|
Scheduler::init();
|
||||||
|
defer { Scheduler::deinit(); };
|
||||||
|
|
||||||
|
f32 val = 0;
|
||||||
|
|
||||||
|
f32 from = 1;
|
||||||
|
f32 to = 2;
|
||||||
|
schedule_animation({
|
||||||
|
.seconds_to_start = 1,
|
||||||
|
.seconds_to_end = 2,
|
||||||
|
.interpolant = &val,
|
||||||
|
.interpolant_type = Interpolant_Type::F32,
|
||||||
|
.from = &from,
|
||||||
|
.to = &to,
|
||||||
|
.interpolation_type = Interpolation_Type::Lerp
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_equal_f64((f64)val, 0.0);
|
||||||
|
|
||||||
|
update_all(1);
|
||||||
|
assert_equal_f64((f64)val, 1.0);
|
||||||
|
|
||||||
|
update_all(0.1);
|
||||||
|
assert_equal_int(abs(val - 1.1) < 0.001, true);
|
||||||
|
|
||||||
|
update_all(0.1);
|
||||||
|
assert_equal_int(abs(val - 1.2) < 0.001, true);
|
||||||
|
|
||||||
|
update_all(0.2);
|
||||||
|
assert_equal_int(abs(val - 1.4) < 0.001, true);
|
||||||
|
|
||||||
|
update_all(1);
|
||||||
|
assert_equal_int(abs(val - 2) < 0.001, true);
|
||||||
|
|
||||||
|
// testing custom type interpolation
|
||||||
|
enum My_Interpolant_Type : u8 {
|
||||||
|
S32
|
||||||
|
};
|
||||||
|
|
||||||
|
register_interpolator([](void* p_from, f32 t, void* p_to, void* p_interpolant) {
|
||||||
|
s32 from = *(s32*)p_from;
|
||||||
|
s32 to = *(s32*)p_to;
|
||||||
|
s32* target = (s32*)p_interpolant;
|
||||||
|
*target = from + (to - from) * t;
|
||||||
|
}, (Interpolant_Type)My_Interpolant_Type::S32, sizeof(s32));
|
||||||
|
|
||||||
|
s32 test = 0;
|
||||||
|
|
||||||
|
s32 s_from = 1;
|
||||||
|
s32 s_to = 11;
|
||||||
|
schedule_animation({
|
||||||
|
.seconds_to_start = 1,
|
||||||
|
.seconds_to_end = 2,
|
||||||
|
.interpolant = &test,
|
||||||
|
.interpolant_type = (Interpolant_Type)My_Interpolant_Type::S32,
|
||||||
|
.from = &s_from,
|
||||||
|
.to = &s_to,
|
||||||
|
.interpolation_type = Interpolation_Type::Lerp
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_equal_int(test, 0);
|
||||||
|
|
||||||
|
update_all(1);
|
||||||
|
assert_equal_int(test, 1);
|
||||||
|
|
||||||
|
update_all(0.1);
|
||||||
|
assert_equal_int(test, 2);
|
||||||
|
|
||||||
|
update_all(0.1);
|
||||||
|
assert_equal_int(test, 3);
|
||||||
|
|
||||||
|
update_all(0.2);
|
||||||
|
assert_equal_int(test, 5);
|
||||||
|
|
||||||
|
update_all(1);
|
||||||
|
assert_equal_int(test, 11);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 main(s32, char**) {
|
||||||
|
defer { print_malloc_stats(); };
|
||||||
|
|
||||||
|
init_printer();
|
||||||
|
defer { deinit_printer(); };
|
||||||
|
testresult result;
|
||||||
|
|
||||||
|
invoke_test(test_array_lists_adding_and_removing);
|
||||||
|
invoke_test(test_array_lists_sorting);
|
||||||
|
invoke_test(test_array_lists_searching);
|
||||||
|
invoke_test(test_array_list_sort_many);
|
||||||
|
invoke_test(test_stack_array_lists);
|
||||||
|
invoke_test(test_bucket_allocator);
|
||||||
|
invoke_test(test_queue);
|
||||||
|
invoke_test(test_hooks);
|
||||||
|
invoke_test(test_scheduler_animations);
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user