checkpoint on rdi_from_dwarf pass, start addressing O(N lg N) hashing problem for type content, use sibling tags, etc.; remove test inputs from data/, just rely on local folder (filled via data server)

This commit is contained in:
Ryan Fleury
2026-06-21 15:53:38 -07:00
parent d3d35e40d7
commit ed6afcb180
16 changed files with 238 additions and 3696 deletions
@@ -1,8 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
bias = (bias^x)&7;
x -= bias;
x *= 2;
x *= x;
x += bias;
@@ -1,126 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
/*
* Program to run in debugger organized to provide tests for
* single threaded stepping, breakpoints, evaluation.
*/
////////////////////////////////
// NOTE(allen): Complex Types
#include <complex.h>
void
c_type_coverage_eval_tests(void){
#if _WIN32
_Fcomplex x = _FCbuild(0.f, 1.f);
_Dcomplex y = _Cbuild(0.f, -1.f);
#else
float complex x = 0.f + 1.f*I;
double complex y = 0.0 - 1.0*I;
#endif
}
////////////////////////////////
// NOTE(allen): Reuse Type Names From Another Module
#include <stdint.h>
typedef struct Basics{
double a;
float b;
unsigned long long c;
long long d;
unsigned int e;
int f;
unsigned short g;
short h;
unsigned char i;
char j;
int z;
} Basics;
typedef struct Basics_Stdint{
double x1;
float x2;
uint64_t x3;
int64_t x4;
uint32_t x5;
int32_t x6;
uint16_t x7;
int16_t x8;
uint8_t x9;
int8_t x0;
} Basics_Stdint;
typedef struct Pair{
int i;
float f;
} Pair;
void
c_versions_of_same_types(void){
Basics basics = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, };
Basics_Stdint basics_stdint = { 1.5f, 1.50000000000001, -1, 1, -2, 2, -4, 4, -8, 8, };
Pair memory_[] = {
{100, 1.f},
{101, 2.f},
{102, 4.f},
{103, 8.f},
{104, 16.f},
{105, 32.f},
};
int x = memory_[3].i + basics.f;
}
////////////////////////////////
//~ NOTE(rjf): Bitfields
typedef struct TypeWithBitfield TypeWithBitfield;
struct TypeWithBitfield
{
int v : 14;
int w : 4;
int x : 32;
int y : 4;
int z : 10;
};
typedef struct BitfieldType64 BitfieldType64;
struct BitfieldType64
{
uint64_t size : 63;
uint64_t is_free : 1;
};
static int mut_xarray[4] = {100, 101, 102, 103};
static float mut_farray[4] = {100.5f, 101.5f, 102.5f, 103.5f};
void
c_type_with_bitfield_usage(void)
{
TypeWithBitfield b = {0};
b.v = 100;
b.w = 6;
b.x = 434512;
b.y = 7;
b.z = 12;
int x = (b.v + b.x);
int y = (b.y - b.z);
int z = (b.w) + 5;
BitfieldType64 b64 = {0};
b64.size = 524288;
b64.is_free = 1;
int abc = mut_xarray[0];
mut_xarray[0] += 1;
abc += mut_xarray[0];
abc += mut_xarray[1];
abc += mut_xarray[2];
float f = mut_farray[0] + mut_farray[1] + mut_farray[2] + mut_farray[3];
int w = 0;
}
@@ -1,10 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
/*
* Program to run in debugger organized to provide tests for
* single threaded stepping, breakpoints, evaluation.
*/
void c_type_coverage_eval_tests(void);
void c_type_with_bitfield_usage(void);
@@ -1,64 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
/*
** Make sure we have an inlined function
*/
#if defined(_MSC_VER)
# define FORCE_INLINE __forceinline
#elif defined(__clang__) || defined(__GNUC__)
# define FORCE_INLINE __attribute__((always_inline))
#else
# error need force inline for this compiler
#endif
////////////////////////////////
// NOTE(allen): Inline Stepping
unsigned int fixed_frac_bits = 5;
static unsigned int bias = 7;
static FORCE_INLINE unsigned int
fixed_mul(unsigned int a, unsigned int b){
unsigned int c = (((a - bias)*(b - bias)) >> fixed_frac_bits) + bias;
return(c);
}
static FORCE_INLINE unsigned int
multi_file_inlinesite(unsigned int x){
// force compiler to generate annotations for code that's inside another file
#include "inline_body.cpp"
return x >> fixed_frac_bits;
}
static unsigned int test_value = 0;
unsigned int
inline_stepping_tests(void){
bias = 15;
// NOTE(nick): Interesting that CL does not generate inline site symbols in order of apperance here unlike clang.
// CL:
// BinaryAnnotations: CodeLengthAndCodeOffset d 0
// BinaryAnnotation Length: 4 bytes (1 bytes padding)
//
// Clang:
// BinaryAnnotations: LineOffset 1 CodeLength d
// BinaryAnnotation Length: 4 bytes (0 bytes padding)
unsigned int x = fixed_mul(5001, 7121);
// CL:
// BinaryAnnotations: CodeOffsetAndLineOffset d File 0 CodeOffsetAndLineOffset 22 LineOffset 1e
// CodeLengthAndCodeOffset 2 3
// BinaryAnnotation Length: 12 bytes (1 bytes padding)
//
// Clang:
// BinaryAnnotations: File 18 LineOffset ffffffe6 CodeOffset d CodeOffsetAndLineOffset 22
// File 0 LineOffset 1e CodeOffset 3 CodeLength 2
// BinaryAnnotation Length: 16 bytes (0 bytes padding)
unsigned int z = multi_file_inlinesite(x);
return(z);
}
File diff suppressed because it is too large Load Diff
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e2b10fe04ef539796a329790987f781e645707a737e32db863f3e49a1766bf5a
size 4763648
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:446e9b14f298e3824edccf61d857108d6100a3c1a3a5dcd7fa7d52fe5a1d6a8d
size 2768548
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7ac765d8dfa6d3a3830b3efc76d8b52f6dd201004e9fead477138ac7b4d1015a
size 264704
@@ -1,60 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if _WIN32
#define export_function extern "C" __declspec(dllexport)
#else
#define export_function extern "C"
#endif
#if _WIN32
# define thread_var __declspec(thread)
#else
# define thread_var __thread
#endif
typedef struct OnlyInModule OnlyInModule;
struct OnlyInModule
{
int x;
int y;
int z;
char *name;
};
typedef struct Basics Basics;
struct Basics
{
int a;
int b;
int c;
int d;
};
static OnlyInModule only_in_module_global =
{
1, 2, 3, "foobar",
};
thread_var float tls_a = 1.015625f;
thread_var int tls_b = -100;
export_function void
dll_tls_eval_test(void)
{
tls_a *= 1.5f;
tls_b *= -2;
only_in_module_global.x += 1;
only_in_module_global.y += 2;
only_in_module_global.z += 3;
}
export_function void
dll_type_eval_tests(void)
{
Basics basics1 = {1, 2, 3, 4};
Basics basics2 = {4, 5, 6, 7};
OnlyInModule only_in_module = {123, 456, 789, "this type is only in the module!"};
int x = 0;
(void)x;
}
Binary file not shown.
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bc2f8b6f96c6bea013dbebcd6f6d84c0f015a361a62bf9158785687402b84311
size 6942720
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:73c47bf20d8d12057fa9e4d12873620f6c860b1bc5d4f831b4925f03e9f7c0b4
size 5518096
@@ -1,119 +0,0 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
static int important_s32 = 0;
static float important_f32 = 0;
#if _WIN32
#include <Windows.h>
#endif
static void
do_something_with_intermediate_values(void)
{
static int another_important_s32 = 0;
static float another_important_f32 = 0;
another_important_s32 = (int)important_f32;
another_important_f32 = (float)important_s32;
#if _WIN32
char buffer[256] = "Hello, World!\n";
buffer[0] += important_s32 + another_important_s32;
buffer[1] += (int)another_important_f32 * important_f32;
OutputDebugStringA(buffer);
#endif
}
static void
store_important_s32(int *ptr)
{
important_s32 = *ptr;
}
static void
store_important_f32(float *ptr)
{
important_f32 = *ptr;
}
void
optimized_build_eval_tests(void)
{
int simple_sum = 0;
for(int i = 0; i < 10000; i += 1)
{
simple_sum += i;
}
store_important_s32(&simple_sum);
do_something_with_intermediate_values();
static struct {float x, y;} vec2s[] =
{
{ 10.f, 76.f },
{ 40.f, 50.f },
{ -230.f, 20.f },
{ 27.f, 27.f },
{ 57.f, -57.f },
{ -37.f, 97.f },
{ 99.f, 67.f },
{ 99.f, 37.f },
{ 99.f, 57.f },
};
{
struct{float x, y;}sum = {0};
int count = sizeof(vec2s)/sizeof(vec2s[0]);
for(int i = 0; i < count; i += 1)
{
sum.x += vec2s[i].x;
sum.y += vec2s[i].y;
}
struct{float x, y;}avg = {sum.x/count, sum.y/count};
float f32 = avg.x * avg.y;
store_important_f32(&f32);
}
do_something_with_intermediate_values();
int factorial = 1;
for(int i = 10; i > 0; i -= 1)
{
factorial *= i;
}
store_important_s32(&factorial);
do_something_with_intermediate_values();
}
////////////////////////////////
// NOTE(allen): Struct Parameters Eval
struct OptimizedBasics{
char a;
unsigned char b;
short c;
unsigned short d;
int e;
unsigned int f;
long long g;
unsigned long long h;
float i;
double j;
};
static void
optimized_struct_parameter_helper(int *ptr, OptimizedBasics basics)
{
basics.a += *ptr;
basics.a += 1;
basics.a += 1;
}
void
optimized_struct_parameters_eval_tests(void)
{
int x = 10;
OptimizedBasics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001};
optimized_struct_parameter_helper(&x, basics);
}
+222 -19
View File
@@ -930,6 +930,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
//- rjf: find all offsets of top-level tag trees across all units //- rjf: find all offsets of top-level tag trees across all units
// //
U64Array *unit_info_root_tag_offs = 0; U64Array *unit_info_root_tag_offs = 0;
U64 *unit_tag_counts__first_pass = 0; // only includes roots + any descendants of roots who *don't* have a 'sibling' attribute
U64 total_root_tag_count = 0; U64 total_root_tag_count = 0;
U64 *total_root_tag_count_ptr = &total_root_tag_count; U64 *total_root_tag_count_ptr = &total_root_tag_count;
lane_sync_u64(&total_root_tag_count_ptr, 0); lane_sync_u64(&total_root_tag_count_ptr, 0);
@@ -938,8 +939,10 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
if(lane_idx() == 0) if(lane_idx() == 0)
{ {
unit_info_root_tag_offs = push_array(scratch.arena, U64Array, unit_count); unit_info_root_tag_offs = push_array(scratch.arena, U64Array, unit_count);
unit_tag_counts__first_pass = push_array(scratch.arena, U64, unit_count);
} }
lane_sync_u64(&unit_info_root_tag_offs, 0); lane_sync_u64(&unit_info_root_tag_offs, 0);
lane_sync_u64(&unit_tag_counts__first_pass, 0);
typedef struct D2R_UnitTagTreeOffChunkNode D2R_UnitTagTreeOffChunkNode; typedef struct D2R_UnitTagTreeOffChunkNode D2R_UnitTagTreeOffChunkNode;
struct D2R_UnitTagTreeOffChunkNode struct D2R_UnitTagTreeOffChunkNode
{ {
@@ -1001,6 +1004,7 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
//- rjf: reading the next tag //- rjf: reading the next tag
DW2_Tag tag = {0}; DW2_Tag tag = {0};
off += dw2_read_tag(scratch3.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag); off += dw2_read_tag(scratch3.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
unit_tag_counts__first_pass[unit_idx] += 1;
//- rjf: look for sibling attribute fast path //- rjf: look for sibling attribute fast path
DW2_Attrib *sibling_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Sibling); DW2_Attrib *sibling_attrib = dw2_attrib_from_kind(&tag, DW_AttribKind_Sibling);
@@ -1104,6 +1108,190 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
lane_sync_u64(&sub_unit_works_count, 0); lane_sync_u64(&sub_unit_works_count, 0);
lane_sync_u64(&sub_unit_works, 0); lane_sync_u64(&sub_unit_works, 0);
////////////////////////////
//- rjf: predict the total number of tags in all units
//
U64 total_tag_count_estimate = 1;
{
U64 tag_size_estimate = 32;
for EachIndex(unit_idx, unit_count)
{
total_tag_count_estimate += dim_1u64(unit_info_tag_ranges[unit_idx]) / tag_size_estimate;
}
}
////////////////////////////
//- rjf: hash all tags / attributes related to type info in all works,
// for combining into type content hashes later. type content hashes
// require combining a tree of several tag hashes - this just does the
// tag hash portion.
//
// record into (off -> hash) map.
//
U64 tag_hash_slots_count = total_tag_count_estimate/8 + 1;
D2R_TagHashNode **tag_hash_slots = 0;
if(lane_idx() == 0)
{
tag_hash_slots = push_array(scratch.arena, D2R_TagHashNode *, tag_hash_slots_count);
}
lane_sync_u64(&tag_hash_slots, 0);
ProfScope("hash all tags / attributes related to type info in all works, for combining into type content hashes later")
{
U64 work_take_idx_ = 0;
U64 *work_take_idx_ptr = &work_take_idx_;
lane_sync_u64(&work_take_idx_ptr, 0);
for(;;)
{
//- rjf: take next work
U64 work_idx = ins_atomic_u64_inc_eval(work_take_idx_ptr) - 1;
if(work_idx >= sub_unit_works_count)
{
break;
}
ProfBegin("hash work");
//- rjf: unpack work
U64 unit_idx = sub_unit_works[work_idx].unit_idx;
Rng1U64 unit_root_tag_idx_range = sub_unit_works[work_idx].root_tag_idx_range;
//- rjf: unpack unit info
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[unit_idx];
Rng1U64 unit_info_tag_range = unit_info_tag_ranges[unit_idx];
//- rjf: hash all relevant tags
for(U64 root_tag_idx = unit_root_tag_idx_range.min;
root_tag_idx < unit_root_tag_idx_range.max;
root_tag_idx += 1)
{
U64 root_tag_start_off = unit_info_root_tag_offs[unit_idx].v[root_tag_idx];
S64 depth = 0;
for(U64 off = root_tag_start_off; contains_1u64(unit_info_tag_range, off) && (depth > 0 || off == root_tag_start_off);)
{
Temp tag_scratch = scratch_begin(&scratch.arena, 1);
U64 start_off = off;
// rjf: read tag
DW2_Tag tag = {0};
off += dw2_read_tag(tag_scratch.arena, raw, unit_parse_ctx, raw->sec[DW_SectionKind_Info].data, off, &tag);
// rjf: determine if we need this tag's hash
B32 need_tag_hash = (tag.kind == DW_TagKind_ArrayType ||
tag.kind == DW_TagKind_ClassType ||
tag.kind == DW_TagKind_EnumerationType ||
tag.kind == DW_TagKind_PointerType ||
tag.kind == DW_TagKind_ReferenceType ||
tag.kind == DW_TagKind_StringType ||
tag.kind == DW_TagKind_StructureType ||
tag.kind == DW_TagKind_SubroutineType ||
tag.kind == DW_TagKind_SubProgram ||
tag.kind == DW_TagKind_Typedef ||
tag.kind == DW_TagKind_UnionType ||
tag.kind == DW_TagKind_PtrToMemberType ||
tag.kind == DW_TagKind_SetType ||
tag.kind == DW_TagKind_BaseType ||
tag.kind == DW_TagKind_ConstType ||
tag.kind == DW_TagKind_FileType ||
tag.kind == DW_TagKind_PackedType ||
tag.kind == DW_TagKind_VolatileType ||
tag.kind == DW_TagKind_RestrictType ||
tag.kind == DW_TagKind_InterfaceType ||
tag.kind == DW_TagKind_UnspecifiedType ||
tag.kind == DW_TagKind_SharedType ||
tag.kind == DW_TagKind_RValueReferenceType ||
tag.kind == DW_TagKind_CoarrayType ||
tag.kind == DW_TagKind_DynamicType ||
tag.kind == DW_TagKind_AtomicType ||
tag.kind == DW_TagKind_ImmutableType ||
tag.kind == DW_TagKind_Namespace);
// rjf: hash <:= tag kind
U64 hash = 0;
if(need_tag_hash)
{
hash = u64_hash_from_seed_str8(hash, str8_struct(&tag.kind));
}
// rjf: hash <:= non-reference attributes
if(need_tag_hash) for(DW2_AttribNode *n = tag.attribs.first; n != 0; n = n->next)
{
if(n->v.val.kind != DW_FormKind_RefAddr &&
n->v.val.kind != DW_FormKind_Ref1 &&
n->v.val.kind != DW_FormKind_Ref2 &&
n->v.val.kind != DW_FormKind_Ref4 &&
n->v.val.kind != DW_FormKind_Ref8 &&
n->v.val.kind != DW_FormKind_RefUData &&
n->v.val.kind != DW_FormKind_RefSup4 &&
n->v.val.kind != DW_FormKind_RefSig8 &&
((tag.kind != DW_TagKind_SubProgram &&
tag.kind != DW_TagKind_FormalParameter) ||
(n->v.attrib_kind != DW_AttribKind_Name &&
n->v.attrib_kind != DW_AttribKind_DeclFile &&
n->v.attrib_kind != DW_AttribKind_DeclLine &&
n->v.attrib_kind != DW_AttribKind_Prototyped &&
n->v.attrib_kind != DW_AttribKind_External &&
n->v.attrib_kind != DW_AttribKind_FrameBase &&
n->v.attrib_kind != DW_AttribKind_Location &&
n->v.attrib_kind != DW_AttribKind_LowPc &&
n->v.attrib_kind != DW_AttribKind_HighPc)))
{
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.kind));
if(n->v.val.string.size != 0)
{
hash = u64_hash_from_seed_str8(hash, n->v.val.string);
}
else if(n->v.val.addr != 0)
{
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.addr));
}
else
{
hash = u64_hash_from_seed_str8(hash, str8_struct(&n->v.val.u128));
}
}
}
// rjf: store
if(need_tag_hash)
{
U64 off_hash = u64_hash_from_str8(str8_struct(&start_off));
U64 slot_idx = off_hash%tag_hash_slots_count;
D2R_TagHashNode *n = push_array(scratch.arena, D2R_TagHashNode, 1);
n->info_off = start_off;
n->hash = hash;
for(B32 inserted = 0; !inserted;)
{
U64 slot_head_val = (U64)ins_atomic_u64_eval(&tag_hash_slots[slot_idx]);
n->next = (D2R_TagHashNode *)slot_head_val;
if(slot_head_val == ins_atomic_u64_eval_cond_assign(&tag_hash_slots[slot_idx], (U64)n, slot_head_val))
{
inserted = 1;
}
}
}
// rjf: tree nav
if(tag.has_children)
{
depth += 1;
}
if(tag.kind == DW_TagKind_Null)
{
depth -= 1;
}
scratch_end(tag_scratch);
if(off == start_off)
{
break;
}
}
}
ProfEnd();
}
lane_sync();
}
//////////////////////////// ////////////////////////////
//- rjf: build built-in types //- rjf: build built-in types
// //
@@ -1128,18 +1316,6 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
lane_sync_u64(&builtin_type_from_kind_map, 0); lane_sync_u64(&builtin_type_from_kind_map, 0);
#define d2r_type_from_builtin_kind(k) ((RDI_TypeKind_FirstBuiltIn <= (k) && (k) <= RDI_TypeKind_LastBuiltIn) ? builtin_type_from_kind_map[k - RDI_TypeKind_FirstBuiltIn] : builtin_type_from_kind_map[RDI_TypeKind_Void]) #define d2r_type_from_builtin_kind(k) ((RDI_TypeKind_FirstBuiltIn <= (k) && (k) <= RDI_TypeKind_LastBuiltIn) ? builtin_type_from_kind_map[k - RDI_TypeKind_FirstBuiltIn] : builtin_type_from_kind_map[RDI_TypeKind_Void])
////////////////////////////
//- rjf: predict the total number of tags in all units
//
U64 total_tag_count_estimate = 1;
{
U64 tag_size_estimate = 32;
for EachIndex(unit_idx, unit_count)
{
total_tag_count_estimate += dim_1u64(unit_info_tag_ranges[unit_idx]) / tag_size_estimate;
}
}
//////////////////////////// ////////////////////////////
//- rjf: gather all unique, to-be-deduplicated tags across all units (types, namespaces) //- rjf: gather all unique, to-be-deduplicated tags across all units (types, namespaces)
// //
@@ -1245,11 +1421,14 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
// functions are not deduplicated, and even if types defined // functions are not deduplicated, and even if types defined
// within many functions match structurally, we consider them // within many functions match structurally, we consider them
// unique, given that they have different definition sites & // unique, given that they have different definition sites &
// names (fully qualified) still. // names (fully qualified) still. (technically, if two UDTs
// match structurally, we could even dedup members - so two
// UDT records, w/ different decl sites/names/etc., but point
// at the same members)
// //
// (2) namespaced by a type - we do *not* want to deduplicate. the // (2) namespaced by a type - we *do* want to deduplicate. the
// root-level type will already be deduplicated, so we'll only // root-level type will be deduplicated, but children are
// produce it once, and that'll catch all sub-types etc. // fragmentary - see (3).
// //
// (3) namespaced by a namespace - we *do* want to deduplicate. the // (3) namespaced by a namespace - we *do* want to deduplicate. the
// children of a namespace are functionally top-level, and even // children of a namespace are functionally top-level, and even
@@ -1257,8 +1436,12 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
// debug info for each unit will contain fragmentary parts of it, // debug info for each unit will contain fragmentary parts of it,
// since presumably unused pieces of the namespace will be stripped. // since presumably unused pieces of the namespace will be stripped.
// thus, we need to visit namespace children as if they're top-level. // thus, we need to visit namespace children as if they're top-level.
//
B32 children_should_be_deduped = 0; B32 children_should_be_deduped = 0;
if(tag.kind == DW_TagKind_Namespace) if(tag.kind == DW_TagKind_Namespace ||
tag.kind == DW_TagKind_ClassType ||
tag.kind == DW_TagKind_StructureType ||
tag.kind == DW_TagKind_UnionType)
{ {
children_should_be_deduped = 1; children_should_be_deduped = 1;
} }
@@ -1381,7 +1564,10 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
} }
} }
//- rjf: hash all tags we need to deduplicate & gather //- rjf: produce tree hash for all tags we need to deduplicate & gather
//
// the tree hash is formed by combining the tag hashes for all dependency tags
//
U64 total_tag_count_this_work = 0; U64 total_tag_count_this_work = 0;
for(D2R_TagNode *tag_n = first_tag_to_dedup; tag_n != 0; tag_n = tag_n->next) for(D2R_TagNode *tag_n = first_tag_to_dedup; tag_n != 0; tag_n = tag_n->next)
{ {
@@ -1412,14 +1598,31 @@ d2r_convert(Arena *arena, D2R_ConvertParams *params)
{ {
next = 0; next = 0;
U64 t_off = t->off; U64 t_off = t->off;
U64 off_hash = u64_hash_from_str8(str8_struct(&t->off));
// rjf: record this task in our seen task table // rjf: record this task in our seen task table
{ {
U64 off_hash = u64_hash_from_str8(str8_struct(&t->off));
U64 slot_idx = off_hash%seen_task_slots_count; U64 slot_idx = off_hash%seen_task_slots_count;
SLLStackPush(seen_task_slots[slot_idx], t); SLLStackPush(seen_task_slots[slot_idx], t);
} }
// rjf: find tag hash for this task
U64 tag_hash = 0;
{
U64 slot_idx = off_hash%tag_hash_slots_count;
for(D2R_TagHashNode *n = tag_hash_slots[slot_idx]; n != 0; n = n->next)
{
if(n->info_off == t_off)
{
tag_hash = n->hash;
break;
}
}
}
// rjf: combine tag hash into tree hash
hash = u64_hash_from_seed_str8(hash, str8_struct(&tag_hash));
// rjf: unpack unit // rjf: unpack unit
Rng1U64 unit_info_tag_range = unit_info_tag_ranges[t->unit_idx]; Rng1U64 unit_info_tag_range = unit_info_tag_ranges[t->unit_idx];
DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[t->unit_idx]; DW2_ParseCtx *unit_parse_ctx = &unit_parse_ctxs[t->unit_idx];
+11
View File
@@ -4,6 +4,17 @@
#ifndef RDI_FROM_DWARF_H #ifndef RDI_FROM_DWARF_H
#define RDI_FROM_DWARF_H #define RDI_FROM_DWARF_H
////////////////////////////////
//~ rjf: Tag Hash Cache Types
typedef struct D2R_TagHashNode D2R_TagHashNode;
struct D2R_TagHashNode
{
D2R_TagHashNode *next;
U64 info_off;
U64 hash;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Unique Tag Tree Deduplication Types //~ rjf: Unique Tag Tree Deduplication Types
+5 -5
View File
@@ -120,7 +120,7 @@ t_delete_dir(String8 path)
if (info.props.flags & FilePropertyFlag_IsFolder) { if (info.props.flags & FilePropertyFlag_IsFolder) {
t_delete_dir(str8f(scratch.arena, "%S/%S", path, info.name)); t_delete_dir(str8f(scratch.arena, "%S/%S", path, info.name));
continue; continue;
} }
@@ -1254,7 +1254,7 @@ t_entry_point(CmdLine *cmdline)
for EachIndex(i, target_indices.count) { for EachIndex(i, target_indices.count) {
if (i == 0) { PrintHeader("Tests"); } if (i == 0) { PrintHeader("Tests"); }
U64 target_idx = target_indices.v[i]; U64 target_idx = target_indices.v[i];
TestInfo *test = g_sorted_test_infos[target_idx]; TestInfo *test = g_sorted_test_infos[target_idx];
@@ -1279,7 +1279,7 @@ t_entry_point(CmdLine *cmdline)
{ {
String8 binary_dir_path = get_process_info()->binary_path; String8 binary_dir_path = get_process_info()->binary_path;
String8 root_dir_path = str8_chop_last_slash(binary_dir_path); String8 root_dir_path = str8_chop_last_slash(binary_dir_path);
g_input_data_dir = str8f(scratch.arena, "%S/data/test_inputs", root_dir_path); g_input_data_dir = str8f(scratch.arena, "%S/local/test_inputs", root_dir_path);
} }
// setup output directory // setup output directory
@@ -1392,10 +1392,10 @@ t_entry_point(CmdLine *cmdline)
for EachElement(i, slowest) { for EachElement(i, slowest) {
Slowest s = slowest[i]; Slowest s = slowest[i];
if (s.target_idx >= test_infos_count) { break; } if (s.target_idx >= test_infos_count) { break; }
TestInfo *test_info = g_sorted_test_infos[s.target_idx]; TestInfo *test_info = g_sorted_test_infos[s.target_idx];
String8 elapsed_time = string_from_elapsed_time(scratch.arena, date_time_from_micro_seconds(s.d)); String8 elapsed_time = string_from_elapsed_time(scratch.arena, date_time_from_micro_seconds(s.d));
fprintf(stderr, " %.*s %.*s/ %.*s %.*s %.*s\n", fprintf(stderr, " %.*s %.*s/ %.*s %.*s %.*s\n",
str8_varg(test_info->layer), str8_varg(test_info->layer),
(int)(layer_max - test_info->layer.size), spaces, (int)(layer_max - test_info->layer.size), spaces,