Skip to content

Commit ad4c15f

Browse files
Improve memory markings
Add test markers. Handle the case of flush range and objects not aligning. Add more test cases. Fix various issues.
1 parent a680358 commit ad4c15f

5 files changed

Lines changed: 147 additions & 29 deletions

File tree

external/tracetooltests

src/hardcode_read.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,11 +1228,14 @@ static void translate_marked_offsets(lava_file_reader& reader, const VkMarkedOff
12281228
{
12291229
if (markings->pMarkingTypes[i] != VK_MARKING_TYPE_DEVICE_ADDRESS_ARM) continue;
12301230
const uint64_t offset = markings->pOffsets[i];
1231-
uint64_t* addr = (uint64_t*)(((char*)ptr) + offset);
1232-
const uint64_t current = *addr;
1231+
void* addr = (char*)ptr + offset;
1232+
uint64_t current = 0;
1233+
// Use memcpy to handle unaligned device address storage.
1234+
memcpy(&current, addr, sizeof(current));
12331235
const uint64_t newval = reader.parent->device_address_remapping.translate_address(current);
1236+
assert(newval != 0 || !reader.run);
12341237
DLOG("%u: Changing memory value at offset %lu from %lu to %lu", (unsigned)i, (unsigned long)offset, (unsigned long)current, (unsigned long)newval);
1235-
*addr = newval;
1238+
memcpy(addr, &newval, sizeof(newval));
12361239
}
12371240
}
12381241

src/hardcode_write.cpp

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,34 +1765,63 @@ void trace_post_vkFlushMappedMemoryRanges(lava_file_writer& writer, VkResult res
17651765
{
17661766
const VkMappedMemoryRange& v = pMemoryRanges[i];
17671767
auto* memory_data = writer.parent->records.VkDeviceMemory_index.at(v.memory);
1768+
assert(memory_data->ptr != nullptr && memory_data->size != 0); // the memory must be memory mapped
1769+
const uint64_t mapped_base = memory_data->offset;
1770+
const uint64_t mapped_limit = memory_data->offset + memory_data->size;
1771+
assert(v.offset >= mapped_base && v.offset <= mapped_limit);
17681772
VkDeviceSize size = v.size;
17691773
if (v.size == VK_WHOLE_SIZE)
17701774
{
1771-
size = memory_data->allocationSize - v.offset;
1775+
size = mapped_limit - v.offset;
17721776
}
1773-
assert(memory_data->ptr != nullptr && memory_data->size != 0); // the memory must be memory mapped
1774-
memory_data->exposed.add_os(v.offset, size);
1777+
assert(v.offset + size <= mapped_limit);
1778+
const uint64_t mapped_start = v.offset;
1779+
const uint64_t mapped_end = mapped_start + size;
1780+
memory_data->exposed.add_os(mapped_start, size);
17751781
// Handle VK_ARM_trace_helpers
17761782
VkMarkedOffsetsARM* ar = (VkMarkedOffsetsARM*)find_extension(&v, VK_STRUCTURE_TYPE_MARKED_OFFSETS_ARM);
17771783
// Handle VK_ARM_explicit_host_updates and/or VK_ARM_trace_helpers
17781784
if (device_data->explicit_host_updates || ar)
17791785
{
17801786
for (auto& pair : memory_data->usage)
17811787
{
1782-
if (pair.first > v.offset + size) continue; // our beginning is later than its end
1788+
if (pair.first > mapped_end) continue; // our beginning is later than its end
17831789
trackedobject* object_data = pair.second;
17841790
assert(pair.first == object_data->offset);
1785-
if (pair.first + object_data->size <= v.offset) continue; // its beginning is later than our end
1791+
if (pair.first + object_data->size <= mapped_start) continue; // its beginning is later than our end
17861792
char* cloneptr = memory_data->clone + object_data->offset;
17871793
char* changedptr = memory_data->ptr + object_data->offset - memory_data->offset;
1788-
uint64_t start = std::max<uint64_t>(object_data->offset, v.offset) - object_data->offset;
1789-
uint64_t end = std::min<uint64_t>(object_data->offset + object_data->size, v.offset + size) - object_data->offset;
1790-
if (ar && v.offset != object_data->offset) // flush range has a different offset than the object, modify the offsets in ar->pOffsets to be relative to start of the object in memory
1794+
uint64_t start = std::max<uint64_t>(object_data->offset, mapped_start) - object_data->offset;
1795+
uint64_t end = std::min<uint64_t>(object_data->offset + object_data->size, mapped_end) - object_data->offset;
1796+
VkMarkedOffsetsARM adjusted = {};
1797+
VkMarkedOffsetsARM* ar_use = nullptr;
1798+
std::vector<VkDeviceSize> adjusted_offsets;
1799+
std::vector<VkMarkingTypeARM> adjusted_types;
1800+
std::vector<VkMarkingSubTypeARM> adjusted_subtypes;
1801+
if (ar && ar->count > 0 && ar->pOffsets && ar->pMarkingTypes)
17911802
{
1792-
// TBD
1793-
assert(false);
1803+
adjusted = *ar;
1804+
adjusted_offsets.reserve(ar->count);
1805+
adjusted_types.reserve(ar->count);
1806+
if (ar->pSubTypes) adjusted_subtypes.reserve(ar->count);
1807+
for (uint32_t mark_i = 0; mark_i < ar->count; mark_i++)
1808+
{
1809+
const uint64_t mark_abs = v.offset + ar->pOffsets[mark_i];
1810+
if (mark_abs < object_data->offset || mark_abs >= object_data->offset + object_data->size) continue;
1811+
adjusted_offsets.push_back(mark_abs - object_data->offset);
1812+
adjusted_types.push_back(ar->pMarkingTypes[mark_i]);
1813+
if (ar->pSubTypes) adjusted_subtypes.push_back(ar->pSubTypes[mark_i]);
1814+
}
1815+
if (!adjusted_offsets.empty())
1816+
{
1817+
adjusted.count = static_cast<uint32_t>(adjusted_offsets.size());
1818+
adjusted.pOffsets = adjusted_offsets.data();
1819+
adjusted.pMarkingTypes = adjusted_types.data();
1820+
adjusted.pSubTypes = ar->pSubTypes ? adjusted_subtypes.data() : nullptr;
1821+
ar_use = &adjusted;
1822+
}
17941823
}
1795-
else uint64_t written = write_out_object(writer, device_data, object_data, cloneptr, changedptr, start, end - start, ar);
1824+
uint64_t written = write_out_object(writer, device_data, object_data, cloneptr, changedptr, start, end - start, ar_use);
17961825
ILOG("vkFlushMappedMemoryRanges[%u] flushing %s[%u] obj(%lu to %lu) object memory offset=%lu object size=%lu flush(off=%u, size=%u)", i, pretty_print_VkObjectType(object_data->object_type),
17971826
(unsigned)object_data->index, (unsigned long)start, (unsigned long)end, (unsigned long)object_data->offset, (unsigned long)object_data->size, (unsigned)v.offset, (unsigned)v.size);
17981827
}

tests/tracing4.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,15 @@ static void trace_4()
312312
VkMappedMemoryRange range = {}; // and only one flush call!
313313
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
314314
range.memory = origin_memory;
315-
range.size = VK_WHOLE_SIZE;
315+
if (map_variant == 2)
316+
{
317+
range.offset = 10;
318+
range.size = 20;
319+
}
320+
else
321+
{
322+
range.size = VK_WHOLE_SIZE;
323+
}
316324
result = trace_vkFlushMappedMemoryRanges(vulkan.device, 1, &range);
317325
check(result);
318326
}
@@ -345,7 +353,15 @@ static void trace_4()
345353
VkMappedMemoryRange range = {}; // and only one flush call! not N calls to flush the entire memory area...
346354
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
347355
range.memory = origin_memory;
348-
range.size = VK_WHOLE_SIZE;
356+
if (map_variant == 2)
357+
{
358+
range.offset = 10;
359+
range.size = 20;
360+
}
361+
else
362+
{
363+
range.size = VK_WHOLE_SIZE;
364+
}
349365
result = trace_vkFlushMappedMemoryRanges(vulkan.device, 1, &range);
350366
check(result);
351367
}
@@ -376,7 +392,15 @@ static void trace_4()
376392
VkMappedMemoryRange range = {}; // and only one flush call! not N calls to flush the entire memory area...
377393
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
378394
range.memory = origin_memory;
379-
range.size = VK_WHOLE_SIZE;
395+
if (map_variant == 2)
396+
{
397+
range.offset = 10;
398+
range.size = 20;
399+
}
400+
else
401+
{
402+
range.size = VK_WHOLE_SIZE;
403+
}
380404
result = trace_vkFlushMappedMemoryRanges(vulkan.device, 1, &range);
381405
check(result);
382406
}

tests/tracing_remap.cpp

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@ static void trace()
1919
vulkan_setup_t vulkan = test_init(TEST_NAME_1, reqs);
2020

2121
VkBuffer buf;
22+
VkBuffer buf2;
2223
VkBufferCreateInfo bufferCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr };
2324
bufferCreateInfo.size = BUFFER_SIZE;
2425
bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR;
2526
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
2627
VkResult result = trace_vkCreateBuffer(vulkan.device, &bufferCreateInfo, nullptr, &buf);
28+
check(result);
29+
result = trace_vkCreateBuffer(vulkan.device, &bufferCreateInfo, nullptr, &buf2);
30+
check(result);
2731

2832
VkMemoryRequirements req;
2933
trace_vkGetBufferMemoryRequirements(vulkan.device, buf, &req);
@@ -35,13 +39,15 @@ static void trace()
3539
VkMemoryAllocateInfo pAllocateMemInfo = {};
3640
pAllocateMemInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
3741
pAllocateMemInfo.memoryTypeIndex = memoryTypeIndex;
38-
pAllocateMemInfo.allocationSize = req.size;
42+
pAllocateMemInfo.allocationSize = aligned_size * 2;
3943
VkDeviceMemory memory = 0;
4044
result = trace_vkAllocateMemory(vulkan.device, &pAllocateMemInfo, nullptr, &memory);
4145
check(result);
4246
assert(memory != 0);
4347

48+
test_marker(vulkan, "Bind buffers");
4449
trace_vkBindBufferMemory(vulkan.device, buf, memory, 0);
50+
trace_vkBindBufferMemory(vulkan.device, buf2, memory, aligned_size);
4551

4652
VkBufferDeviceAddressInfo bdainfo = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr };
4753
bdainfo.buffer = buf;
@@ -57,6 +63,7 @@ static void trace()
5763
ar.pMarkingTypes = markingTypes.data();
5864
ar.pSubTypes = subTypes.data();
5965

66+
test_marker(vulkan, "Device address at first byte - " + std::to_string(address));
6067
char* ptr = nullptr;
6168
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
6269
check(result);
@@ -71,27 +78,82 @@ static void trace()
7178
testFlushMemory(vulkan, memory, 0, pAllocateMemInfo.allocationSize, true, &ar);
7279
trace_vkUnmapMemory(vulkan.device, memory);
7380

74-
// 8-byte-aligned address
81+
test_marker(vulkan, "Device address at bytes 32 and 128"); // 8-byte-aligned address
7582
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
7683
check(result);
7784
uint64_t* u64ptr = (uint64_t*)ptr;
85+
u64ptr[4] = address; // second address, on 8 byte aligned boundary
7886
u64ptr[16] = address; // second address, on 8 byte aligned boundary
79-
ar.count = 1; // we only changed one value
80-
offsets[0] = 16 * sizeof(uint64_t); // and it is here
87+
ar.count = 2; // we only changed one value
88+
offsets[0] = 4 * sizeof(uint64_t); // and it is here
89+
offsets[1] = 16 * sizeof(uint64_t); // and it is here too
8190
testFlushMemory(vulkan, memory, 0, pAllocateMemInfo.allocationSize, true, &ar);
8291
trace_vkUnmapMemory(vulkan.device, memory);
8392

84-
// 4-byte-aligned address that is _not_ 8 byte aligned
93+
test_marker(vulkan, "Partial flush");
94+
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
95+
check(result);
96+
u64ptr = (uint64_t*)ptr;
97+
const VkDeviceSize flush_offset = 64 * sizeof(uint64_t);
98+
const VkDeviceSize flush_size = 32 * sizeof(uint64_t);
99+
const VkDeviceSize marked_offset = flush_offset + (4 * sizeof(uint64_t));
100+
u64ptr[marked_offset / sizeof(uint64_t)] = address;
101+
ar.count = 1;
102+
offsets[0] = marked_offset - flush_offset;
103+
testFlushMemory(vulkan, memory, flush_offset, flush_size, true, &ar);
104+
trace_vkUnmapMemory(vulkan.device, memory);
105+
106+
test_marker(vulkan, "Flush with mapped offset");
107+
result = trace_vkMapMemory(vulkan.device, memory, 192, VK_WHOLE_SIZE, 0, (void**)&ptr);
108+
check(result);
109+
u64ptr = (uint64_t*)ptr;
110+
*u64ptr = address;
111+
ar.count = 1;
112+
offsets[0] = 0;
113+
testFlushMemory(vulkan, memory, 192, 64, true, &ar);
114+
trace_vkUnmapMemory(vulkan.device, memory);
115+
116+
test_marker(vulkan, "Flush with mapped offset and limited window");
117+
result = trace_vkMapMemory(vulkan.device, memory, 200, 64, 0, (void**)&ptr);
118+
check(result);
119+
u64ptr = (uint64_t*)ptr;
120+
u64ptr[1] = address;
121+
ar.count = 1;
122+
offsets[0] = 8;
123+
testFlushMemory(vulkan, memory, 200, VK_WHOLE_SIZE, true, &ar);
124+
trace_vkUnmapMemory(vulkan.device, memory);
125+
126+
test_marker(vulkan, "Flush with out of bounds offset");
127+
result = trace_vkMapMemory(vulkan.device, memory, 8, 64, 0, (void**)&ptr);
128+
check(result);
129+
ar.count = 1;
130+
offsets[0] = UINT32_MAX;
131+
testFlushMemory(vulkan, memory, 8, VK_WHOLE_SIZE, true, &ar);
132+
trace_vkUnmapMemory(vulkan.device, memory);
133+
134+
test_marker(vulkan, "Device address on a 4 byte alignment");
85135
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
86136
check(result);
87137
u64ptr = (uint64_t*)(ptr + 4);
88138
u64ptr[64] = address; // add one more address at non-8-byte-aligned boundary
89139
ar.count = 1; // we still only changed one value
90-
offsets[0] = 64 * sizeof(uint32_t); // and it is here
140+
offsets[0] = 64 * sizeof(uint64_t) + 4; // and it is here
91141
testFlushMemory(vulkan, memory, 0, pAllocateMemInfo.allocationSize, true, &ar);
92142
trace_vkUnmapMemory(vulkan.device, memory);
93143

94-
// no address changes -- send empty address list
144+
test_marker(vulkan, "Device address in a second buffer and flush covering both");
145+
result = trace_vkMapMemory(vulkan.device, memory, 0, VK_WHOLE_SIZE, 0, (void**)&ptr);
146+
check(result);
147+
u64ptr = (uint64_t*)(ptr + aligned_size);
148+
u64ptr[0] = address;
149+
u64ptr[1] = address;
150+
ar.count = 2;
151+
offsets[0] = aligned_size;
152+
offsets[1] = aligned_size + 8;
153+
testFlushMemory(vulkan, memory, 0, VK_WHOLE_SIZE, true, &ar);
154+
trace_vkUnmapMemory(vulkan.device, memory);
155+
156+
test_marker(vulkan, "No address changes, empty address list sent");
95157
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
96158
check(result);
97159
u64ptr = (uint64_t*)ptr;
@@ -100,30 +162,30 @@ static void trace()
100162
testFlushMemory(vulkan, memory, 0, pAllocateMemInfo.allocationSize, true, &ar);
101163
trace_vkUnmapMemory(vulkan.device, memory);
102164

103-
// no address changes -- no address list
165+
test_marker(vulkan, "No address changes, no address list sent");
104166
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
105167
check(result);
106168
u64ptr = (uint64_t*)ptr;
107169
u64ptr[20] = 0;
108170
testFlushMemory(vulkan, memory, 0, pAllocateMemInfo.allocationSize, true, nullptr);
109171
trace_vkUnmapMemory(vulkan.device, memory);
110172

111-
// no address changes -- no info bit, just flush
173+
test_marker(vulkan, "No address changes, just flush");
112174
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
113175
check(result);
114176
u64ptr = (uint64_t*)ptr;
115177
u64ptr[21] = 0;
116178
testFlushMemory(vulkan, memory, 0, pAllocateMemInfo.allocationSize, false, nullptr);
117179
trace_vkUnmapMemory(vulkan.device, memory);
118180

119-
// no address changes -- no flush even
181+
test_marker(vulkan, "No address changes, no flush");
120182
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
121183
check(result);
122184
u64ptr = (uint64_t*)ptr;
123185
u64ptr[22] = 0;
124186
trace_vkUnmapMemory(vulkan.device, memory);
125187

126-
// remove all addresses -- notice their removal if we scan for them
188+
test_marker(vulkan, "Reset buffer back to dead pattern and flush");
127189
result = trace_vkMapMemory(vulkan.device, memory, 0, pAllocateMemInfo.allocationSize, 0, (void**)&ptr);
128190
check(result);
129191
u32ptr = (uint32_t*)ptr;

0 commit comments

Comments
 (0)