Skip to content

Commit 1d4e749

Browse files
committed
Add Core and hyperthreading + core type info, use e-cores for EventQueue
1 parent 5039802 commit 1d4e749

8 files changed

Lines changed: 368 additions & 6 deletions

File tree

src/engine/Base/Base.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ set( sysList
5858
)
5959

6060
set( threadList
61+
${engineBase}/Thread/Core.cpp
62+
${engineBase}/Thread/Core.h
6163
${engineBase}/Thread/EventQueue.cpp
6264
${engineBase}/Thread/EventQueue.h
6365
${engineBase}/Thread/GlobalMemory.cpp

src/engine/Base/BaseDecls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,6 @@ struct Array;
4242
template<typename T>
4343
class DynamicArray;
4444

45+
struct Core;
46+
4547
#endif // BASE_DECLS_H

src/engine/Base/Sys/OSThread.cpp

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929
*/
3030

3131
#ifdef _MSC_VER
32+
#include <intrin.h>
33+
3234
#include "Windows.h"
3335

3436
#include <powerbase.h>
@@ -44,10 +46,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4446
#include <pthread.h>
4547
#endif
4648

49+
#include "Thread/Core.h"
4750
#include "Thread/ThreadCommon.h"
51+
#include "SysAllocator.h"
4852
#include "Bit.h"
4953
#include "DynamicArray.h"
5054
#include "Timer.h"
55+
#include "Parser.h"
5156

5257
#include "CPUInfo.h"
5358

@@ -82,6 +87,9 @@ void OSThread::SetAffinity( const uint32 newCore ) {
8287

8388
if ( !ret ) {
8489
Log::Warn( "SetThreadGroupAffinity error: %i", GetLastError() );
90+
baseMaxFrequency = 1.0;
91+
92+
return;
8593
}
8694

8795
// PROCESSOR_POWER_INFORMATION, which is missing from windows headers
@@ -127,7 +135,7 @@ void OSThread::SetAffinity( const uint32 newCore ) {
127135
int ret = pthread_setaffinity_np( thread, sizeof( cpu ), &cpu );
128136

129137
if ( ret != 0 ) {
130-
Log::Warn( "sched_setaffinity error: %s", strerror( errno ) );
138+
Log::Warn( "pthread_setaffinity_np error: %s", strerror( errno ) );
131139
}
132140
#endif
133141
}
@@ -185,4 +193,173 @@ double OSThread::GetMaxFrequencyScale() {
185193
#else // Can't set thread affinity on apple, so no point in scaling by max frequency
186194
return 1.0;
187195
#endif
196+
}
197+
198+
struct File {
199+
FILE* file;
200+
uint32_t size;
201+
202+
File( const std::string& path, const char* mode ) {
203+
file = fopen( path.c_str(), mode );
204+
205+
if ( !file ) {
206+
printf( "Failed to open file: %s, mode: %s\n", path.c_str(), mode );
207+
printf( strerror( errno ) );
208+
exit( 1 );
209+
}
210+
211+
fseek( file, 0, SEEK_END );
212+
size = ftell( file );
213+
214+
fseek( file, 0, 0 );
215+
}
216+
217+
File( const std::string& path, const std::string& path2, const char* mode ) {
218+
file = fopen( path.c_str(), mode );
219+
220+
if ( !file ) {
221+
file = fopen( path2.c_str(), mode );
222+
223+
if( !file ) {
224+
Log::Warn( "Failed to open file: %s, mode: %s\n", path.c_str(), mode );
225+
Log::Warn( strerror( errno ) );
226+
}
227+
}
228+
229+
fseek( file, 0, SEEK_END );
230+
size = ftell( file );
231+
232+
fseek( file, 0, 0 );
233+
}
234+
235+
~File() {
236+
fclose( file );
237+
}
238+
239+
std::string ReadAll() {
240+
std::string data;
241+
data.resize( size );
242+
size = fread( data.data(), sizeof( char ), size, file );
243+
244+
data.resize( size );
245+
data.shrink_to_fit();
246+
247+
return data;
248+
}
249+
};
250+
251+
Core OSThread::GetCoreInfo() {
252+
#ifdef _MSC_VER
253+
DWORD size = 0;
254+
255+
GetLogicalProcessorInformationEx( RelationProcessorCore, nullptr, &size );
256+
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* buf = ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ) sysAllocator.Alloc( size, 64 );
257+
bool ret = GetLogicalProcessorInformationEx( RelationProcessorCore, buf, &size );
258+
259+
if ( !ret ) {
260+
Log::Warn( "GetLogicalProcessorInformationEx error: %i", GetLastError() );
261+
262+
return {
263+
.type = CORE_UNKNOWN,
264+
.hyperthreading = false,
265+
.maxFrequencyScale = GetMaxFrequencyScale()
266+
};
267+
}
268+
269+
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* coreInfo = ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ) ( ( ( byte* ) buf ) + core * buf->Size );
270+
271+
return {
272+
.type = coreInfo->Processor.EfficiencyClass ? CORE_PERFORMANCE : CORE_EFFICIENCY,
273+
.hyperthreading = coreInfo->Processor.Flags == LTP_PC_SMT,
274+
.maxFrequencyScale = GetMaxFrequencyScale()
275+
};
276+
#elifndef __APPLE__
277+
return {
278+
.type = CORE_UNKNOWN,
279+
.hyperthreading = false,
280+
.maxFrequencyScale = GetMaxFrequencyScale()
281+
};
282+
#else
283+
return {
284+
.type = CORE_PERFORMANCE,
285+
.hyperthreading = false,
286+
.maxFrequencyScale = GetMaxFrequencyScale()
287+
};
288+
#endif
289+
}
290+
291+
#ifdef __linux__
292+
bool IsHyperthreadingEnabled() {
293+
File cpuInfoFile { "/proc/cpuinfo", "r" };
294+
std::string cpuInfo = cpuInfoFile.ReadAll();
295+
296+
StringView v { cpuInfo.c_str(), cpuInfo.size() };
297+
298+
int physicalCores = 0;
299+
int logicalCores = 0;
300+
301+
do {
302+
StringView o = Parse( v );
303+
304+
if ( o == "cpu" ) {
305+
if ( Parse( v ) == "cores" ) {
306+
Parse( v ); // :
307+
Str::ParseInt( physicalCores, std::string( o.memory, o.size ) );
308+
}
309+
} else if ( o == "siblings" ) {
310+
Parse( v ); // :
311+
Str::ParseInt( logicalCores, std::string( o.memory, o.size ) );
312+
}
313+
} while ( v.size && !( physicalCores && logicalCores ) );
314+
315+
return physicalCores == logicalCores;
316+
}
317+
#elif __APPLE__
318+
bool IsHyperthreadingEnabled() {
319+
return false;
320+
}
321+
#endif
322+
323+
std::string GetCPUModel() {
324+
#ifdef _MSC_VER
325+
int info[4] {};
326+
std::string model;
327+
328+
static constexpr uint32 infoSize = 4 * sizeof( int );
329+
330+
model.resize( 65 );
331+
332+
__cpuid( info, 0x80000002 );
333+
memcpy( model.data(), info, infoSize );
334+
335+
__cpuid( info, 0x80000003 );
336+
memcpy( model.data() + infoSize, info, infoSize );
337+
338+
__cpuid( info, 0x80000004 );
339+
memcpy( model.data() + 2 * infoSize, info, infoSize );
340+
341+
model.resize( strlen( model.c_str() ) ); // Avoid the ugly NUL characters in logger
342+
343+
return model;
344+
#elifdef __linux__
345+
File cpuInfoFile { "/proc/cpuinfo", "r" };
346+
std::string cpuInfo = cpuInfoFile.ReadAll();
347+
348+
StringView v { cpuInfo.c_str(), cpuInfo.size() };
349+
350+
do {
351+
StringView o = Parse( v );
352+
353+
if ( o == "model" ) {
354+
if ( Parse( v ) == "name" ) {
355+
Parse( v ); // :
356+
return Parse( v );
357+
}
358+
}
359+
} while ( v.size );
360+
361+
return "Unknown";
362+
#else
363+
return "Unknown";
364+
#endif
188365
}

src/engine/Base/Sys/OSThread.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3636
#endif
3737

3838
#include "Int.h"
39+
#include "BaseDecls.h"
3940

4041
struct OSThread {
4142
#ifdef _MSC_VER
@@ -52,6 +53,13 @@ struct OSThread {
5253
void Init();
5354
void SetAffinity( const uint32 core );
5455
double GetMaxFrequencyScale();
56+
Core GetCoreInfo();
5557
};
5658

59+
#if defined( __linux__ ) || defined( __APPLE__ )
60+
bool IsHyperthreadingEnabled();
61+
#endif
62+
63+
std::string GetCPUModel();
64+
5765
#endif // OS_THREAD_H

src/engine/Base/Thread/Core.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
=============================================================================
3+
Daemon-Vulkan BSD Source Code
4+
Copyright (c) 2025-2026 Reaper
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are met:
9+
* Redistributions of source code must retain the above copyright
10+
notice, this list of conditions and the following disclaimer.
11+
* Redistributions in binary form must reproduce the above copyright
12+
notice, this list of conditions and the following disclaimer in the
13+
documentation and/or other materials provided with the distribution.
14+
* Neither the name of the Reaper nor the
15+
names of its contributors may be used to endorse or promote products
16+
derived from this software without specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
19+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
DISCLAIMED. IN NO EVENT SHALL REAPER BE LIABLE FOR ANY
22+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
=============================================================================
29+
*/
30+
31+
#include "common/Common.h"
32+
33+
#include "Sys/CPUInfo.h"
34+
35+
#include "Core.h"
36+
37+
std::string CPU::FormatCoreInfo() {
38+
std::string out = model + "\n";
39+
40+
for ( Core* core = cores; core < cores + CPU_CORES; core++ ) {
41+
out += Str::Format( "\nCore %2u: max freq: %f, hyperthreading: %s",
42+
core - cores, core->maxFrequencyScale, core->hyperthreading );
43+
}
44+
45+
return out;
46+
}
47+
48+
CPU cpu;

src/engine/Base/Thread/Core.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
=============================================================================
3+
Daemon-Vulkan BSD Source Code
4+
Copyright (c) 2025-2026 Reaper
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without
8+
modification, are permitted provided that the following conditions are met:
9+
* Redistributions of source code must retain the above copyright
10+
notice, this list of conditions and the following disclaimer.
11+
* Redistributions in binary form must reproduce the above copyright
12+
notice, this list of conditions and the following disclaimer in the
13+
documentation and/or other materials provided with the distribution.
14+
* Neither the name of the Reaper nor the
15+
names of its contributors may be used to endorse or promote products
16+
derived from this software without specific prior written permission.
17+
18+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
19+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
DISCLAIMED. IN NO EVENT SHALL REAPER BE LIABLE FOR ANY
22+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
=============================================================================
29+
*/
30+
31+
#ifndef CORE_H
32+
#define CORE_H
33+
34+
#include <string>
35+
36+
#include "Int.h"
37+
38+
#include "ThreadCommon.h"
39+
40+
enum CoreType : uint8 {
41+
CORE_UNKNOWN,
42+
CORE_PERFORMANCE,
43+
CORE_EFFICIENCY
44+
};
45+
46+
struct Core {
47+
CoreType type;
48+
bool hyperthreading;
49+
double maxFrequencyScale;
50+
uint16 coreLatencies[MAX_THREADS];
51+
};
52+
53+
struct CPU {
54+
Core cores[MAX_THREADS];
55+
56+
uint64 performanceCores = 0;
57+
uint64 efficiencyCores = 0;
58+
59+
std::string model;
60+
61+
std::string FormatCoreInfo();
62+
};
63+
64+
extern CPU cpu;
65+
66+
#endif // CORE_H

0 commit comments

Comments
 (0)