mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-03-04 08:37:33 +00:00
Implement basic TSC calibration
This commit is contained in:
parent
50a6d1a074
commit
4e37240cb9
@ -51,6 +51,8 @@ public:
|
||||
void deleteProcess(Process *proc);
|
||||
Process *findProcessById(pid_t pid) const;
|
||||
|
||||
long getTscFreq();
|
||||
|
||||
void *kalloc(std::size_t size,
|
||||
std::size_t align = __STDCPP_DEFAULT_NEW_ALIGNMENT__);
|
||||
void kfree(void *ptr, std::size_t size);
|
||||
@ -113,6 +115,8 @@ private:
|
||||
|
||||
UmtxChain m_umtx_chains[2][c_umtx_chains]{};
|
||||
|
||||
std::atomic<long> m_tsc_freq{0};
|
||||
|
||||
mutable shared_mutex m_proc_mtx;
|
||||
utils::LinkedNode<Process> *m_processes = nullptr;
|
||||
utils::kmap<utils::kstring, Ref<EventFlag>> m_event_flags;
|
||||
|
@ -24,7 +24,8 @@ KernelContext::KernelContext() {
|
||||
pthread_mutex_init(&m_heap_mtx, &mtx_attr);
|
||||
pthread_mutexattr_destroy(&mtx_attr);
|
||||
|
||||
std::printf("orbis::KernelContext initialized, addr=%p", this);
|
||||
std::printf("orbis::KernelContext initialized, addr=%p\n", this);
|
||||
std::printf("TSC frequency: %lu\n", getTscFreq());
|
||||
}
|
||||
KernelContext::~KernelContext() {}
|
||||
|
||||
@ -73,6 +74,49 @@ Process *KernelContext::findProcessById(pid_t pid) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
long KernelContext::getTscFreq() {
|
||||
auto cal_tsc = []() -> long {
|
||||
const long timer_freq = 1'000'000'000;
|
||||
|
||||
// Calibrate TSC
|
||||
constexpr int samples = 40;
|
||||
long rdtsc_data[samples];
|
||||
long timer_data[samples];
|
||||
long error_data[samples];
|
||||
|
||||
struct timespec ts0;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts0);
|
||||
long sec_base = ts0.tv_sec;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
usleep(200);
|
||||
error_data[i] = (__builtin_ia32_lfence(), __builtin_ia32_rdtsc());
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
rdtsc_data[i] = (__builtin_ia32_lfence(), __builtin_ia32_rdtsc());
|
||||
timer_data[i] = ts.tv_nsec + (ts.tv_sec - sec_base) * 1'000'000'000;
|
||||
}
|
||||
|
||||
// Compute average TSC
|
||||
long acc = 0;
|
||||
for (int i = 0; i < samples - 1; i++) {
|
||||
acc += (rdtsc_data[i + 1] - rdtsc_data[i]) * timer_freq /
|
||||
(timer_data[i + 1] - timer_data[i]);
|
||||
}
|
||||
|
||||
// Rounding
|
||||
acc /= (samples - 1);
|
||||
constexpr long grain = 1'000'000;
|
||||
return grain * (acc / grain + long{(acc % grain) > (grain / 2)});
|
||||
};
|
||||
|
||||
long freq = m_tsc_freq.load();
|
||||
if (freq)
|
||||
return freq;
|
||||
m_tsc_freq.compare_exchange_strong(freq, cal_tsc());
|
||||
return m_tsc_freq.load();
|
||||
}
|
||||
|
||||
void *KernelContext::kalloc(std::size_t size, std::size_t align) {
|
||||
size = (size + (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) &
|
||||
~(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1);
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "KernelContext.hpp"
|
||||
#include "sys/sysproto.hpp"
|
||||
|
||||
orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
||||
@ -232,7 +233,7 @@ orbis::SysResult orbis::sys___sysctl(Thread *thread, ptr<sint> name,
|
||||
return ErrorCode::INVAL;
|
||||
}
|
||||
|
||||
*(uint64_t *)old = 1000000000ull;
|
||||
*(uint64_t *)old = g_context.getTscFreq();
|
||||
return {};
|
||||
|
||||
default:
|
||||
|
Loading…
x
Reference in New Issue
Block a user