summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/process.h13
-rw-r--r--src/core/hle/kernel/scheduler.cpp28
-rw-r--r--src/core/hle/kernel/scheduler.h19
-rw-r--r--src/core/hle/kernel/svc.cpp61
-rw-r--r--src/core/hle/kernel/svc.h31
-rw-r--r--src/core/hle/kernel/thread.h11
6 files changed, 128 insertions, 35 deletions
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 148478488..8d2616c79 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -202,6 +202,16 @@ public:
202 return is_64bit_process; 202 return is_64bit_process;
203 } 203 }
204 204
205 /// Gets the total running time of the process instance in ticks.
206 u64 GetCPUTimeTicks() const {
207 return total_process_running_time_ticks;
208 }
209
210 /// Updates the total running time, adding the given ticks to it.
211 void UpdateCPUTimeTicks(u64 ticks) {
212 total_process_running_time_ticks += ticks;
213 }
214
205 /** 215 /**
206 * Loads process-specifics configuration info with metadata provided 216 * Loads process-specifics configuration info with metadata provided
207 * by an executable. 217 * by an executable.
@@ -305,6 +315,9 @@ private:
305 /// specified by metadata provided to the process during loading. 315 /// specified by metadata provided to the process during loading.
306 bool is_64bit_process = true; 316 bool is_64bit_process = true;
307 317
318 /// Total running time for the process in ticks.
319 u64 total_process_running_time_ticks = 0;
320
308 /// Per-process handle table for storing created object handles in. 321 /// Per-process handle table for storing created object handles in.
309 HandleTable handle_table; 322 HandleTable handle_table;
310 323
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 1342c597e..5a5f4cef1 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -9,6 +9,7 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/arm/arm_interface.h" 10#include "core/arm/arm_interface.h"
11#include "core/core.h" 11#include "core/core.h"
12#include "core/core_timing.h"
12#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/scheduler.h" 15#include "core/hle/kernel/scheduler.h"
@@ -34,6 +35,10 @@ Thread* Scheduler::GetCurrentThread() const {
34 return current_thread.get(); 35 return current_thread.get();
35} 36}
36 37
38u64 Scheduler::GetLastContextSwitchTicks() const {
39 return last_context_switch_time;
40}
41
37Thread* Scheduler::PopNextReadyThread() { 42Thread* Scheduler::PopNextReadyThread() {
38 Thread* next = nullptr; 43 Thread* next = nullptr;
39 Thread* thread = GetCurrentThread(); 44 Thread* thread = GetCurrentThread();
@@ -54,7 +59,10 @@ Thread* Scheduler::PopNextReadyThread() {
54} 59}
55 60
56void Scheduler::SwitchContext(Thread* new_thread) { 61void Scheduler::SwitchContext(Thread* new_thread) {
57 Thread* previous_thread = GetCurrentThread(); 62 Thread* const previous_thread = GetCurrentThread();
63 Process* const previous_process = Core::CurrentProcess();
64
65 UpdateLastContextSwitchTime(previous_thread, previous_process);
58 66
59 // Save context for previous thread 67 // Save context for previous thread
60 if (previous_thread) { 68 if (previous_thread) {
@@ -78,8 +86,6 @@ void Scheduler::SwitchContext(Thread* new_thread) {
78 // Cancel any outstanding wakeup events for this thread 86 // Cancel any outstanding wakeup events for this thread
79 new_thread->CancelWakeupTimer(); 87 new_thread->CancelWakeupTimer();
80 88
81 auto* const previous_process = Core::CurrentProcess();
82
83 current_thread = new_thread; 89 current_thread = new_thread;
84 90
85 ready_queue.remove(new_thread->GetPriority(), new_thread); 91 ready_queue.remove(new_thread->GetPriority(), new_thread);
@@ -102,6 +108,22 @@ void Scheduler::SwitchContext(Thread* new_thread) {
102 } 108 }
103} 109}
104 110
111void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
112 const u64 prev_switch_ticks = last_context_switch_time;
113 const u64 most_recent_switch_ticks = CoreTiming::GetTicks();
114 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
115
116 if (thread != nullptr) {
117 thread->UpdateCPUTimeTicks(update_ticks);
118 }
119
120 if (process != nullptr) {
121 process->UpdateCPUTimeTicks(update_ticks);
122 }
123
124 last_context_switch_time = most_recent_switch_ticks;
125}
126
105void Scheduler::Reschedule() { 127void Scheduler::Reschedule() {
106 std::lock_guard<std::mutex> lock(scheduler_mutex); 128 std::lock_guard<std::mutex> lock(scheduler_mutex);
107 129
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 2c94641ec..c63032b7d 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -17,6 +17,8 @@ class ARM_Interface;
17 17
18namespace Kernel { 18namespace Kernel {
19 19
20class Process;
21
20class Scheduler final { 22class Scheduler final {
21public: 23public:
22 explicit Scheduler(Core::ARM_Interface& cpu_core); 24 explicit Scheduler(Core::ARM_Interface& cpu_core);
@@ -31,6 +33,9 @@ public:
31 /// Gets the current running thread 33 /// Gets the current running thread
32 Thread* GetCurrentThread() const; 34 Thread* GetCurrentThread() const;
33 35
36 /// Gets the timestamp for the last context switch in ticks.
37 u64 GetLastContextSwitchTicks() const;
38
34 /// Adds a new thread to the scheduler 39 /// Adds a new thread to the scheduler
35 void AddThread(SharedPtr<Thread> thread, u32 priority); 40 void AddThread(SharedPtr<Thread> thread, u32 priority);
36 41
@@ -64,6 +69,19 @@ private:
64 */ 69 */
65 void SwitchContext(Thread* new_thread); 70 void SwitchContext(Thread* new_thread);
66 71
72 /**
73 * Called on every context switch to update the internal timestamp
74 * This also updates the running time ticks for the given thread and
75 * process using the following difference:
76 *
77 * ticks += most_recent_ticks - last_context_switch_ticks
78 *
79 * The internal tick timestamp for the scheduler is simply the
80 * most recent tick count retrieved. No special arithmetic is
81 * applied to it.
82 */
83 void UpdateLastContextSwitchTime(Thread* thread, Process* process);
84
67 /// Lists all thread ids that aren't deleted/etc. 85 /// Lists all thread ids that aren't deleted/etc.
68 std::vector<SharedPtr<Thread>> thread_list; 86 std::vector<SharedPtr<Thread>> thread_list;
69 87
@@ -73,6 +91,7 @@ private:
73 SharedPtr<Thread> current_thread = nullptr; 91 SharedPtr<Thread> current_thread = nullptr;
74 92
75 Core::ARM_Interface& cpu_core; 93 Core::ARM_Interface& cpu_core;
94 u64 last_context_switch_time = 0;
76 95
77 static std::mutex scheduler_mutex; 96 static std::mutex scheduler_mutex;
78}; 97};
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index a5302d924..4e490e2b5 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -467,6 +467,37 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
467 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, 467 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
468 info_sub_id, handle); 468 info_sub_id, handle);
469 469
470 enum class GetInfoType : u64 {
471 // 1.0.0+
472 AllowedCpuIdBitmask = 0,
473 AllowedThreadPrioBitmask = 1,
474 MapRegionBaseAddr = 2,
475 MapRegionSize = 3,
476 HeapRegionBaseAddr = 4,
477 HeapRegionSize = 5,
478 TotalMemoryUsage = 6,
479 TotalHeapUsage = 7,
480 IsCurrentProcessBeingDebugged = 8,
481 ResourceHandleLimit = 9,
482 IdleTickCount = 10,
483 RandomEntropy = 11,
484 PerformanceCounter = 0xF0000002,
485 // 2.0.0+
486 ASLRRegionBaseAddr = 12,
487 ASLRRegionSize = 13,
488 NewMapRegionBaseAddr = 14,
489 NewMapRegionSize = 15,
490 // 3.0.0+
491 IsVirtualAddressMemoryEnabled = 16,
492 PersonalMmHeapUsage = 17,
493 TitleId = 18,
494 // 4.0.0+
495 PrivilegedProcessId = 19,
496 // 5.0.0+
497 UserExceptionContextAddr = 20,
498 ThreadTickCount = 0xF0000002,
499 };
500
470 const auto* current_process = Core::CurrentProcess(); 501 const auto* current_process = Core::CurrentProcess();
471 const auto& vm_manager = current_process->VMManager(); 502 const auto& vm_manager = current_process->VMManager();
472 503
@@ -529,6 +560,36 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
529 "(STUBBED) Attempted to query user exception context address, returned 0"); 560 "(STUBBED) Attempted to query user exception context address, returned 0");
530 *result = 0; 561 *result = 0;
531 break; 562 break;
563 case GetInfoType::ThreadTickCount: {
564 constexpr u64 num_cpus = 4;
565 if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
566 return ERR_INVALID_COMBINATION_KERNEL;
567 }
568
569 const auto thread =
570 current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
571 if (!thread) {
572 return ERR_INVALID_HANDLE;
573 }
574
575 auto& system = Core::System::GetInstance();
576 const auto& scheduler = system.CurrentScheduler();
577 const auto* const current_thread = scheduler.GetCurrentThread();
578 const bool same_thread = current_thread == thread;
579
580 const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
581 u64 out_ticks = 0;
582 if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
583 const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
584
585 out_ticks = thread_ticks + (CoreTiming::GetTicks() - prev_ctx_ticks);
586 } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
587 out_ticks = CoreTiming::GetTicks() - prev_ctx_ticks;
588 }
589
590 *result = out_ticks;
591 break;
592 }
532 default: 593 default:
533 UNIMPLEMENTED(); 594 UNIMPLEMENTED();
534 } 595 }
diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h
index 554a5e328..b06aac4ec 100644
--- a/src/core/hle/kernel/svc.h
+++ b/src/core/hle/kernel/svc.h
@@ -24,37 +24,6 @@ struct PageInfo {
24 u64 flags; 24 u64 flags;
25}; 25};
26 26
27/// Values accepted by svcGetInfo
28enum class GetInfoType : u64 {
29 // 1.0.0+
30 AllowedCpuIdBitmask = 0,
31 AllowedThreadPrioBitmask = 1,
32 MapRegionBaseAddr = 2,
33 MapRegionSize = 3,
34 HeapRegionBaseAddr = 4,
35 HeapRegionSize = 5,
36 TotalMemoryUsage = 6,
37 TotalHeapUsage = 7,
38 IsCurrentProcessBeingDebugged = 8,
39 ResourceHandleLimit = 9,
40 IdleTickCount = 10,
41 RandomEntropy = 11,
42 PerformanceCounter = 0xF0000002,
43 // 2.0.0+
44 ASLRRegionBaseAddr = 12,
45 ASLRRegionSize = 13,
46 NewMapRegionBaseAddr = 14,
47 NewMapRegionSize = 15,
48 // 3.0.0+
49 IsVirtualAddressMemoryEnabled = 16,
50 PersonalMmHeapUsage = 17,
51 TitleId = 18,
52 // 4.0.0+
53 PrivilegedProcessId = 19,
54 // 5.0.0+
55 UserExceptionContextAddr = 20,
56};
57
58void CallSVC(u32 immediate); 27void CallSVC(u32 immediate);
59 28
60} // namespace Kernel 29} // namespace Kernel
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index f4d7bd235..4a6e11239 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -258,6 +258,14 @@ public:
258 return last_running_ticks; 258 return last_running_ticks;
259 } 259 }
260 260
261 u64 GetTotalCPUTimeTicks() const {
262 return total_cpu_time_ticks;
263 }
264
265 void UpdateCPUTimeTicks(u64 ticks) {
266 total_cpu_time_ticks += ticks;
267 }
268
261 s32 GetProcessorID() const { 269 s32 GetProcessorID() const {
262 return processor_id; 270 return processor_id;
263 } 271 }
@@ -378,7 +386,8 @@ private:
378 u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application 386 u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application
379 u32 current_priority = 0; ///< Current thread priority, can be temporarily changed 387 u32 current_priority = 0; ///< Current thread priority, can be temporarily changed
380 388
381 u64 last_running_ticks = 0; ///< CPU tick when thread was last running 389 u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks.
390 u64 last_running_ticks = 0; ///< CPU tick when thread was last running
382 391
383 s32 processor_id = 0; 392 s32 processor_id = 0;
384 393