mirror of https://github.com/RPCS3/rpcs3.git
SPU: Task-based SPURS limiter
This commit is contained in:
parent
c4334f5142
commit
ad42a2b89a
|
@ -1837,6 +1837,11 @@ void spu_thread::cpu_task()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spurs_addr && group->max_run != 6)
|
||||||
|
{
|
||||||
|
group->spurs_running++;
|
||||||
|
}
|
||||||
|
|
||||||
if (jit)
|
if (jit)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
|
@ -1884,6 +1889,14 @@ void spu_thread::cpu_task()
|
||||||
|
|
||||||
allow_interrupts_in_cpu_work = false;
|
allow_interrupts_in_cpu_work = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spurs_addr && group->max_run != 6)
|
||||||
|
{
|
||||||
|
if (group->spurs_running.exchange(0))
|
||||||
|
{
|
||||||
|
group->spurs_running.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void spu_thread::cpu_work()
|
void spu_thread::cpu_work()
|
||||||
|
@ -5469,12 +5482,71 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||||
|
|
||||||
case SPU_RdEventStat:
|
case SPU_RdEventStat:
|
||||||
{
|
{
|
||||||
|
const bool is_spurs_task_wait = pc == 0x11a8 && group->max_run != 6 && spurs_addr;
|
||||||
|
|
||||||
|
if (is_spurs_task_wait)
|
||||||
|
{
|
||||||
|
const u32 prev_running = group->spurs_running.fetch_op([](u32& x)
|
||||||
|
{
|
||||||
|
if (x)
|
||||||
|
{
|
||||||
|
x--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}).first;
|
||||||
|
|
||||||
|
if (prev_running == group->max_run)
|
||||||
|
{
|
||||||
|
group->spurs_running.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const u32 mask1 = ch_events.load().mask;
|
const u32 mask1 = ch_events.load().mask;
|
||||||
|
|
||||||
auto events = get_events(mask1, false, true);
|
auto events = get_events(mask1, false, true);
|
||||||
|
|
||||||
|
const auto wait_spurs_task = [&]
|
||||||
|
{
|
||||||
|
if (is_spurs_task_wait)
|
||||||
|
{
|
||||||
|
// Wait for other threads to complete their tasks (temporarily)
|
||||||
|
if (!is_stopped())
|
||||||
|
{
|
||||||
|
const u32 prev_running = group->spurs_running.fetch_op([max = group->max_run](u32& x)
|
||||||
|
{
|
||||||
|
if (x < max)
|
||||||
|
{
|
||||||
|
x++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}).first;
|
||||||
|
|
||||||
|
if (prev_running >= group->max_run)
|
||||||
|
{
|
||||||
|
const u64 before = get_system_time();
|
||||||
|
thread_ctrl::wait_on(group->spurs_running, prev_running, 10000);
|
||||||
|
|
||||||
|
// Check for missed waiting (due to thread-state notification or value change)
|
||||||
|
const u32 new_running = group->spurs_running;
|
||||||
|
|
||||||
|
if (!is_stopped() && new_running >= group->max_run && get_system_time() - before < 1500)
|
||||||
|
{
|
||||||
|
thread_ctrl::wait_on(group->spurs_running, new_running, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
group->spurs_running++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (events.count)
|
if (events.count)
|
||||||
{
|
{
|
||||||
|
wait_spurs_task();
|
||||||
return events.events & mask1;
|
return events.events & mask1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5490,7 +5562,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||||
const u32 old_raddr = raddr;
|
const u32 old_raddr = raddr;
|
||||||
|
|
||||||
// Does not need to safe-access reservation if LR is the only event masked
|
// Does not need to safe-access reservation if LR is the only event masked
|
||||||
// Because it's either an access violation or a livelock if an invalid memory is passed
|
// Because it's either an access violation or a live-lock if an invalid memory is passed
|
||||||
if (raddr && mask1 > SPU_EVENT_LR)
|
if (raddr && mask1 > SPU_EVENT_LR)
|
||||||
{
|
{
|
||||||
auto area = vm::get(vm::any, raddr);
|
auto area = vm::get(vm::any, raddr);
|
||||||
|
@ -5504,7 +5576,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||||
}
|
}
|
||||||
else if (area)
|
else if (area)
|
||||||
{
|
{
|
||||||
// Ensure possesion over reservation memory so it won't be deallocated
|
// Ensure possession over reservation memory so it won't be de-allocated
|
||||||
auto [base_addr, shm_] = area->peek(raddr);
|
auto [base_addr, shm_] = area->peek(raddr);
|
||||||
|
|
||||||
if (shm_)
|
if (shm_)
|
||||||
|
@ -5690,6 +5762,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||||
thread_ctrl::wait_on(state, old, 100);
|
thread_ctrl::wait_on(state, old, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wait_spurs_task();
|
||||||
wakeup_delay();
|
wakeup_delay();
|
||||||
|
|
||||||
if (is_paused(state - cpu_flag::suspend))
|
if (is_paused(state - cpu_flag::suspend))
|
||||||
|
|
|
@ -1057,7 +1057,7 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
|
||||||
default: return CELL_ESTAT;
|
default: return CELL_ESTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 max_threads = group->max_run;
|
const u32 max_threads = group->max_num;
|
||||||
|
|
||||||
group->join_state = 0;
|
group->join_state = 0;
|
||||||
group->exit_status = 0;
|
group->exit_status = 0;
|
||||||
|
|
|
@ -289,6 +289,7 @@ struct lv2_spu_group
|
||||||
atomic_t<s32> exit_status; // SPU Thread Group Exit Status
|
atomic_t<s32> exit_status; // SPU Thread Group Exit Status
|
||||||
atomic_t<u32> join_state; // flags used to detect exit cause and signal
|
atomic_t<u32> join_state; // flags used to detect exit cause and signal
|
||||||
atomic_t<u32> running = 0; // Number of running threads
|
atomic_t<u32> running = 0; // Number of running threads
|
||||||
|
atomic_t<u32> spurs_running = 0;
|
||||||
atomic_t<u32> stop_count = 0;
|
atomic_t<u32> stop_count = 0;
|
||||||
atomic_t<u32> wait_term_count = 0;
|
atomic_t<u32> wait_term_count = 0;
|
||||||
u32 waiter_spu_index = -1; // Index of SPU executing a waiting syscall
|
u32 waiter_spu_index = -1; // Index of SPU executing a waiting syscall
|
||||||
|
|
Loading…
Reference in New Issue