Uploading data to D3D12 PBO from WSL 2 get very slow performance.
Here is the translation of your text into English:
I uploaded data to a DirectX PBO in WSL 2, and the code is shown below. The performance is very slow; uploading 512 * 512 * 274 * 2 = 143,654,912 bytes took 470 milliseconds. I recorded a kernel trace log and, after analysis, extracted 120 functions with excessively long execution times (the log is attached). There are two scenarios:
- After returning to user mode from a page fault interrupt, the execution time of the
exit_to_user_mode_prepare
function is exceptionally long, ranging from 1 to 10 milliseconds (normally it should be less than 1 microsecond). - During task switching in the idle process scheduler, when the CPU time slice is switched to another process, the execution time of the
default_idle
function is also exceptionally long, ranging from 1 to 10 milliseconds (normally it should be less than 1 microsecond).
These two scenarios combined account for most of the memcpy
time, totaling 430 milliseconds, with the overall copy time being approximately 470–500 milliseconds. Moreover, these kernel activities are serialized and run on different CPU cores.
My WSL 2 environment is as follows:
wsl --version
WSL version: 2.3.26.0
Kernel version: 5.15.167.4-1
WSLg version: 1.0.65
MSRDC version: 1.2.5620
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26100.1-240331-1435.ge-release
Windows version: 10.0.19044.5371
The code is as follows:
size_t dataSize = 512 * 512 * 274 * 2;
BYTE* data = new BYTE[dataSize];
D3D12_HEAP_PROPERTIES pboHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_CUSTOM);
pboHeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
pboHeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_L0;
// Create PBO (Pixel Buffer Object)
D3D12_RESOURCE_DESC pboResourceDesc = CD3DX12_RESOURCE_DESC::Buffer(dataSize);
ComPtr<ID3D12Resource> pboBuffer;
CHK(device->CreateCommittedResource(
&pboHeapProperties,
D3D12_HEAP_FLAG_NONE,
&pboResourceDesc,
D3D12_RESOURCE_STATE_COMMON,
nullptr,
IID_PPV_ARGS(&pboBuffer)
));
// Upload data to PBO
void* pPBOData;
CHK(pboBuffer->Map(0, nullptr, &pPBOData));
auto start = std::chrono::high_resolution_clock::now();
memcpy(pPBOData, data, dataSize);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::cout << "mesa pbo memcpy: " << duration << " ms" << std::endl;
pboBuffer->Unmap(0, nullptr);
delete[] data;
The log of functions with excessively long execution times is as follows:
Line 14596 - main-8596 [005] d.... 59090.531799: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 14597 - main-8596 [005] d.... 59090.536728: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 14963 - <idle>-0 [004] d.... 59090.536811: default_idle <-default_idle_call
Line 14964 - main-8596 [005] ..... 59090.538477: down_read_trylock <-do_user_addr_fault
Line 14988 - main-8596 [005] d.... 59090.538480: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 14989 - <idle>-0 [000] d.... 59090.541368: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 15380 - <idle>-0 [003] d.... 59090.541408: default_idle <-default_idle_call
Line 15381 - main-8596 [005] ..... 59090.545148: down_read_trylock <-do_user_addr_fault
Line 15405 - main-8596 [005] d.... 59090.545154: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 15406 - main-8596 [005] d.... 59090.546740: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 15822 - <idle>-0 [002] d.... 59090.546819: default_idle <-default_idle_call
Line 15823 - <idle>-0 [000] d.... 59090.551491: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 16239 - main-8596 [005] d.... 59090.551784: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 16240 - <idle>-0 [004] d.... 59090.556749: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 16986 - <idle>-0 [000] d.... 59090.556811: default_idle <-default_idle_call
Line 16987 - main-8596 [005] ..... 59090.558568: down_read_trylock <-do_user_addr_fault
Line 17011 - main-8596 [005] d.... 59090.558573: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 17012 - <idle>-0 [003] d.... 59090.561637: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 17403 - <idle>-0 [003] d.... 59090.561680: default_idle <-default_idle_call
Line 17404 - main-8596 [005] ..... 59090.565168: down_read_trylock <-do_user_addr_fault
Line 17429 - main-8596 [005] d.... 59090.565172: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 17430 - main-8596 [005] d.... 59090.566737: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 18087 - <idle>-0 [004] d.... 59090.566891: default_idle <-default_idle_call
Line 18088 - <idle>-0 [003] d.... 59090.571774: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 18504 - main-8596 [005] d.... 59090.571965: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 18505 - main-8596 [005] d.... 59090.576734: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 18667 - <idle>-0 [000] d.... 59090.576790: default_idle <-default_idle_call
Line 18668 - main-8596 [005] ..... 59090.578686: down_read_trylock <-do_user_addr_fault
Line 18692 - main-8596 [005] d.... 59090.578691: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 18693 - <idle>-0 [003] d.... 59090.581938: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 19084 - <idle>-0 [000] d.... 59090.581979: default_idle <-default_idle_call
Line 19085 - main-8596 [005] ..... 59090.585449: down_read_trylock <-do_user_addr_fault
Line 19109 - main-8596 [005] d.... 59090.585454: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 19110 - main-8596 [005] d.... 59090.586743: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 19544 - <idle>-0 [004] d.... 59090.586804: default_idle <-default_idle_call
Line 19545 - <idle>-0 [003] d.... 59090.592042: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 19961 - main-8596 [005] d.... 59090.592175: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 19962 - main-8596 [005] d.... 59090.596734: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 20250 - <idle>-0 [004] d.... 59090.596831: default_idle <-default_idle_call
Line 20251 - main-8596 [005] ..... 59090.598873: down_read_trylock <-do_user_addr_fault
Line 20275 - main-8596 [005] d.... 59090.598876: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 20276 - <idle>-0 [000] d.... 59090.602174: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 20786 - <idle>-0 [003] d.... 59090.602217: default_idle <-default_idle_call
Line 20787 - main-8596 [005] ..... 59090.605744: down_read_trylock <-do_user_addr_fault
Line 20964 - main-8596 [005] d.... 59090.606776: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 20965 - <idle>-0 [000] d.... 59090.612332: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 21424 - main-8596 [005] d.... 59090.612445: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 21425 - <idle>-0 [002] d.... 59090.614087: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 21611 - <idle>-0 [002] d.... 59090.614121: default_idle <-default_idle_call
Line 21612 - main-8596 [005] d.... 59090.616729: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 21905 - <idle>-0 [004] d.... 59090.616822: default_idle <-default_idle_call
Line 21906 - main-8596 [005] ..... 59090.619251: down_read_trylock <-do_user_addr_fault
Line 21930 - main-8596 [005] d.... 59090.619257: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 21931 - <idle>-0 [000] d.... 59090.622507: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 22341 - <idle>-0 [003] d.... 59090.622554: default_idle <-default_idle_call
Line 22342 - <idle>-0 [000] d.... 59090.625236: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 22936 - main-8596 [005] d.... 59090.626742: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 22937 - <idle>-0 [001] d.... 59090.632274: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 23587 - main-8596 [005] d.... 59090.632729: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 23588 - main-8596 [005] d.... 59090.636762: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 23659 - main-8596 [005] d.... 59090.636773: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 23660 - main-8596 [005] ..... 59090.639431: down_read_trylock <-do_user_addr_fault
Line 23684 - main-8596 [005] d.... 59090.639435: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 23685 - <idle>-0 [003] d.... 59090.642740: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 24185 - <idle>-0 [000] d.... 59090.642808: default_idle <-default_idle_call
Line 24186 - main-8596 [005] ..... 59090.646261: down_read_trylock <-do_user_addr_fault
Line 24282 - main-8596 [005] d.... 59090.646790: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 24283 - <idle>-0 [003] d.... 59090.652844: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 24742 - main-8596 [005] d.... 59090.652964: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 24743 - main-8596 [005] d.... 59090.656738: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 24814 - main-8596 [005] d.... 59090.656750: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 24815 - main-8596 [005] ..... 59090.659599: down_read_trylock <-do_user_addr_fault
Line 24839 - main-8596 [005] d.... 59090.659604: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 24840 - <idle>-0 [003] d.... 59090.662976: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 25274 - <idle>-0 [000] d.... 59090.663091: default_idle <-default_idle_call
Line 25275 - main-8596 [005] ..... 59090.666356: down_read_trylock <-do_user_addr_fault
Line 25371 - main-8596 [005] d.... 59090.666748: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 25372 - main-8596 [005] ..... 59090.673042: down_read_trylock <-do_user_addr_fault
Line 25831 - <idle>-0 [000] d.... 59090.673247: default_idle <-default_idle_call
Line 25832 - main-8596 [005] d.... 59090.676738: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 25903 - main-8596 [005] d.... 59090.676749: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 25904 - main-8596 [005] ..... 59090.679784: down_read_trylock <-do_user_addr_fault
Line 25928 - main-8596 [005] d.... 59090.679789: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 25929 - <idle>-0 [003] d.... 59090.683300: irq_enter_rcu <-sysvec_hyperv_stimer0
Line 26429 - <idle>-0 [000] d.... 59090.683411: default_idle <-default_idle_call
Line 26430 - main-8596 [005] ..... 59090.686380: down_read_trylock <-do_user_addr_fault
Line 26527 - main-8596 [005] d.... 59090.686742: exit_to_user_mode_prepare <-irqentry_exit_to_user_mode
Line 26528 - main-8596 [005] ..... 59090.693073: down_read_trylock <-do_user_addr_fault
Line 26987 - <idle>-0 [000] d.... 59090.693533: default_idle <-default_idle_call
Line 26988 - main-8596 [005] d....