forked from arrayfire/arrayfire
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevice_manager.cpp
More file actions
182 lines (161 loc) · 6.04 KB
/
device_manager.cpp
File metadata and controls
182 lines (161 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*******************************************************
* Copyright (c) 2019, ArrayFire
* All rights reserved.
*
* This file is distributed under 3-clause BSD license.
* The complete license agreement can be obtained at:
* http://arrayfire.com/licenses/BSD-3-Clause
********************************************************/
#include <common/DefaultMemoryManager.hpp>
#include <common/err_common.hpp>
#include <common/graphics_common.hpp>
#include <device_manager.hpp>
#include <memory.hpp>
#include <af/version.h>
#include <cctype>
#include <sstream>
using common::memory::MemoryManagerBase;
using std::string;
#ifdef CPUID_CAPABLE
CPUInfo::CPUInfo()
: mVendorId("")
, mModelName("")
, mNumSMT(0)
, mNumCores(0)
, mNumLogCpus(0)
, mIsHTT(false) {
// Get vendor name EAX=0
CPUID cpuID1(1, 0);
mIsHTT = cpuID1.EDX() & HTT_POS;
CPUID cpuID0(0, 0);
uint32_t HFS = cpuID0.EAX();
mVendorId += string(reinterpret_cast<const char*>(&cpuID0.EBX()), 4);
mVendorId += string(reinterpret_cast<const char*>(&cpuID0.EDX()), 4);
mVendorId += string(reinterpret_cast<const char*>(&cpuID0.ECX()), 4);
string upVId = mVendorId;
for_each(upVId.begin(), upVId.end(),
[](char& in) { in = static_cast<char>(::toupper(in)); });
// Get num of cores
if (upVId.find("INTEL") != std::string::npos) {
mVendorId = "Intel";
if (HFS >= 11) {
for (int lvl = 0; lvl < MAX_INTEL_TOP_LVL; ++lvl) {
CPUID cpuID4(0x0B, lvl);
uint32_t currLevel = (LVL_TYPE & cpuID4.ECX()) >> 8U;
switch (currLevel) {
case 0x01: mNumSMT = LVL_CORES & cpuID4.EBX(); break;
case 0x02: mNumLogCpus = LVL_CORES & cpuID4.EBX(); break;
default: break;
}
}
// Fixes Possible divide by zero error
// TODO: Fix properly
mNumCores = mNumLogCpus / (mNumSMT == 0 ? 1 : mNumSMT);
} else {
if (HFS >= 1) {
mNumLogCpus = (cpuID1.EBX() >> 16U) & 0xFFU;
if (HFS >= 4) {
mNumCores = 1 + ((CPUID(4, 0).EAX() >> 26U) & 0x3FU);
}
}
if (mIsHTT) {
if (!(mNumCores > 1)) {
mNumCores = 1;
mNumLogCpus = (mNumLogCpus >= 2 ? mNumLogCpus : 2U);
}
} else {
mNumCores = mNumLogCpus = 1;
}
}
} else if (upVId.find("AMD") != std::string::npos) {
mVendorId = "AMD";
if (HFS >= 1) {
mNumLogCpus = (cpuID1.EBX() >> 16U) & 0xFFU;
if (CPUID(0x80000000, 0).EAX() >= 8U) {
mNumCores = 1 + ((CPUID(0x80000008, 0).ECX() & 0xFFU));
}
}
if (mIsHTT) {
if (!(mNumCores > 1)) {
mNumCores = 1;
mNumLogCpus = (mNumLogCpus >= 2 ? mNumLogCpus : 2);
}
} else {
mNumCores = mNumLogCpus = 1;
}
} else {
mVendorId = "Unknown";
}
// Get processor brand string
// This seems to be working for both Intel & AMD vendors
for (unsigned i = 0x80000002; i < 0x80000005; ++i) {
CPUID cpuID(i, 0);
mModelName += string(reinterpret_cast<const char*>(&cpuID.EAX()), 4);
mModelName += string(reinterpret_cast<const char*>(&cpuID.EBX()), 4);
mModelName += string(reinterpret_cast<const char*>(&cpuID.ECX()), 4);
mModelName += string(reinterpret_cast<const char*>(&cpuID.EDX()), 4);
}
mModelName.shrink_to_fit();
}
#else
CPUInfo::CPUInfo()
: mVendorId("Unknown")
, mModelName("Unknown")
, mNumSMT(1)
, mNumCores(1)
, mNumLogCpus(1)
, mIsHTT(false) {}
#endif
namespace cpu {
DeviceManager::DeviceManager()
: queues(MAX_QUEUES)
, fgMngr(new graphics::ForgeManager())
, memManager(new common::DefaultMemoryManager(
getDeviceCount(), common::MAX_BUFFERS,
AF_MEM_DEBUG || AF_CPU_MEM_DEBUG)) {
// Use the default ArrayFire memory manager
std::unique_ptr<cpu::Allocator> deviceMemoryManager(new cpu::Allocator());
memManager->setAllocator(std::move(deviceMemoryManager));
memManager->initialize();
}
DeviceManager& DeviceManager::getInstance() {
static auto* my_instance = new DeviceManager();
return *my_instance;
}
CPUInfo DeviceManager::getCPUInfo() const { return cinfo; }
void DeviceManager::resetMemoryManager() {
// Replace with default memory manager
std::unique_ptr<MemoryManagerBase> mgr(
new common::DefaultMemoryManager(getDeviceCount(), common::MAX_BUFFERS,
AF_MEM_DEBUG || AF_CPU_MEM_DEBUG));
setMemoryManager(std::move(mgr));
}
void DeviceManager::setMemoryManager(
std::unique_ptr<MemoryManagerBase> newMgr) {
std::lock_guard<std::mutex> l(mutex);
// It's possible we're setting a memory manager and the default memory
// manager still hasn't been initialized, so initialize it anyways so we
// don't inadvertently reset to it when we first call memoryManager()
memoryManager();
// Calls shutdown() on the existing memory manager
if (memManager) { memManager->shutdownAllocator(); }
memManager = std::move(newMgr);
// Set the backend memory manager for this new manager to register native
// functions correctly.
std::unique_ptr<cpu::Allocator> deviceMemoryManager(new cpu::Allocator());
memManager->setAllocator(std::move(deviceMemoryManager));
memManager->initialize();
}
void DeviceManager::setMemoryManagerPinned(
std::unique_ptr<MemoryManagerBase> newMgr) {
UNUSED(newMgr);
UNUSED(this);
AF_ERROR("Using pinned memory with CPU is not supported",
AF_ERR_NOT_SUPPORTED);
}
void DeviceManager::resetMemoryManagerPinned() {
// This is a NOOP - we should never set a pinned memory manager in the first
// place for the CPU backend, but don't throw in case backend-agnostic
// functions that operate on all memory managers need to call this
}
} // namespace cpu