Skip to content

Commit e7b9902

Browse files
authored
proposed fix for non windows systems (#41)
* prposed fix for non windows systems * bug fix * fixed in main * commented unecessary tests and benchmarks
1 parent 16bc78b commit e7b9902

3 files changed

Lines changed: 104 additions & 109 deletions

File tree

‎examples/ICRA2026/eval_manipulator.cpp‎

Lines changed: 97 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,6 @@
99

1010
#include "../../tests/test_helper/test_helper.hpp"
1111

12-
#include <fcntl.h> // _O_WRONLY
13-
#include <io.h> // _open, _dup, _dup2, _close
14-
15-
#define WIN32_LEAN_AND_MEAN
16-
#ifndef _WIN32_WINNT
17-
#define _WIN32_WINNT 0x0A00 // Windows 10+
18-
#endif
19-
#include <algorithm>
20-
#include <mutex>
21-
#include <thread>
22-
#include <unordered_set>
23-
#include <windows.h>
24-
2512
#include <cassert>
2613
#include <fstream>
2714
#include <stdexcept>
@@ -225,75 +212,40 @@ inline World get_kitchen_open_doors() {
225212
return world;
226213
}
227214

228-
// ------------------------------ Helper functions ------------------------------
229-
struct IOSilencer {
230-
int saved_stdout_fd = -1;
231-
int null_fd = -1;
232-
std::streambuf* old_cout = nullptr;
233-
std::streambuf* old_cerr = nullptr;
234-
std::ofstream null_stream;
235-
236-
IOSilencer() {
237-
// Flush buffers
238-
std::cout.flush();
239-
std::cerr.flush();
240-
fflush(stdout);
241-
242-
// Redirect std::cout and std::cerr to /dev/null
243-
null_stream.open("NUL"); // Windows null device
244-
old_cout = std::cout.rdbuf();
245-
old_cerr = std::cerr.rdbuf();
246-
std::cout.rdbuf(null_stream.rdbuf());
247-
std::cerr.rdbuf(null_stream.rdbuf());
248-
249-
// Redirect printf (C stdout)
250-
saved_stdout_fd = _dup(_fileno(stdout));
251-
null_fd = _open("NUL", _O_WRONLY);
252-
_dup2(null_fd, _fileno(stdout));
253-
}
254-
255-
~IOSilencer() {
256-
std::cout.rdbuf(old_cout);
257-
std::cerr.rdbuf(old_cerr);
258-
fflush(stdout);
259-
260-
_dup2(saved_stdout_fd, _fileno(stdout));
261-
_close(null_fd);
262-
_close(saved_stdout_fd);
263-
}
264-
};
265-
266-
struct CpuRow {
267-
ULONG id; // CpuSet.Id (stable handle for SetThreadSelectedCpuSets)
268-
WORD group; // processor group
269-
ULONG lpi; // LogicalProcessorIndex (info only)
270-
ULONG core; // CoreIndex (same for SMT siblings)
271-
BYTE eff; // EfficiencyClass (0 = most performant if hybrid)
272-
bool ok; // Allocated & !Parked
273-
};
215+
// ============================================================================
216+
// Cross-platform performance/thread helpers
217+
// ============================================================================
218+
#ifdef _WIN32
219+
#define WIN32_LEAN_AND_MEAN
220+
#ifndef _WIN32_WINNT
221+
#define _WIN32_WINNT 0x0A00
222+
#endif
223+
#include <algorithm>
224+
#include <iostream>
225+
#include <unordered_set>
226+
#include <vector>
227+
#include <windows.h>
274228

275229
static std::vector<GROUP_AFFINITY> pick_physical_cores(size_t N) {
276230
std::vector<GROUP_AFFINITY> picks;
277231

278-
// --- Preferred: CPU set API ---
279232
DWORD len = 0;
280-
GetSystemCpuSetInformation(nullptr, 0, &len, nullptr, 0); // note: nullptr process
233+
GetSystemCpuSetInformation(nullptr, 0, &len, nullptr, 0);
281234
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER && len > 0) {
282235
std::vector<unsigned char> buf(len);
283236
if (GetSystemCpuSetInformation(reinterpret_cast<SYSTEM_CPU_SET_INFORMATION*>(buf.data()),
284237
(ULONG) buf.size(), &len, nullptr, 0)) {
285238
std::unordered_set<ULONG> seen_core;
286239
BYTE min_eff = 255, max_eff = 0;
287-
288-
BYTE* p = buf.data();
289-
BYTE* end = p + len;
290240
struct Row {
291241
GROUP_AFFINITY ga;
292242
ULONG core;
293243
BYTE eff;
294244
};
295245
std::vector<Row> rows;
296246

247+
BYTE* p = buf.data();
248+
BYTE* end = p + len;
297249
while (p < end) {
298250
auto* info = reinterpret_cast<SYSTEM_CPU_SET_INFORMATION*>(p);
299251
if (info->Type == CpuSetInformation) {
@@ -305,21 +257,17 @@ static std::vector<GROUP_AFFINITY> pick_physical_cores(size_t N) {
305257
r.core = c.CoreIndex;
306258
r.eff = c.EfficiencyClass;
307259
rows.push_back(r);
308-
if (r.eff < min_eff)
309-
min_eff = r.eff;
310-
if (r.eff > max_eff)
311-
max_eff = r.eff;
260+
min_eff = std::min(min_eff, r.eff);
261+
max_eff = std::max(max_eff, r.eff);
312262
}
313263
}
314264
p += info->Size;
315265
}
316266

317267
if (!rows.empty()) {
318268
bool hybrid = (min_eff != max_eff);
319-
std::sort(rows.begin(), rows.end(),
320-
[](const Row& a, const Row& b) { return a.core < b.core; });
321-
322-
for (const auto& r: rows) {
269+
std::sort(rows.begin(), rows.end(), [](auto& a, auto& b) { return a.core < b.core; });
270+
for (auto& r: rows) {
323271
if (hybrid && r.eff != min_eff)
324272
continue; // prefer P-cores
325273
if (seen_core.insert(r.core).second) {
@@ -332,53 +280,97 @@ static std::vector<GROUP_AFFINITY> pick_physical_cores(size_t N) {
332280
}
333281
}
334282

335-
if (!picks.empty())
336-
return picks;
337-
338-
// --- Fallback: LogicalProcessorInformationEx ---
339-
DWORD bytes = 0;
340-
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &bytes);
341-
std::vector<unsigned char> buf2(bytes);
342-
if (GetLogicalProcessorInformationEx(RelationProcessorCore,
343-
reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(buf2.data()), &bytes)) {
344-
345-
BYTE* p2 = buf2.data();
346-
BYTE* end2 = p2 + bytes;
347-
while (p2 < end2) {
348-
auto* ex = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(p2);
349-
if (ex->Relationship == RelationProcessorCore) {
350-
const GROUP_AFFINITY& g = ex->Processor.GroupMask[0];
351-
if (g.Mask) {
352-
KAFFINITY first = g.Mask & (~g.Mask + 1);
353-
GROUP_AFFINITY ga{};
354-
ga.Group = g.Group;
355-
ga.Mask = first;
356-
picks.push_back(ga);
357-
if (picks.size() == N)
358-
break;
283+
// fallback if empty
284+
if (picks.empty()) {
285+
DWORD bytes = 0;
286+
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &bytes);
287+
std::vector<unsigned char> buf2(bytes);
288+
if (GetLogicalProcessorInformationEx(RelationProcessorCore,
289+
reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(buf2.data()), &bytes)) {
290+
BYTE* p = buf2.data();
291+
BYTE* end = p + bytes;
292+
while (p < end) {
293+
auto* ex = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(p);
294+
if (ex->Relationship == RelationProcessorCore) {
295+
const GROUP_AFFINITY& g = ex->Processor.GroupMask[0];
296+
if (g.Mask) {
297+
KAFFINITY first = g.Mask & (~g.Mask + 1);
298+
GROUP_AFFINITY ga{};
299+
ga.Group = g.Group;
300+
ga.Mask = first;
301+
picks.push_back(ga);
302+
if (picks.size() == N)
303+
break;
304+
}
359305
}
306+
p += ex->Size;
360307
}
361-
p2 += ex->Size;
362308
}
363309
}
364310

365311
return picks;
366312
}
367313

368-
369-
static inline void raise_process_priority() {
314+
inline void raise_process_priority() {
370315
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
371316
}
372317

373-
static inline void configure_current_thread_for_performance() {
318+
inline void configure_current_thread_for_performance() {
374319
THREAD_POWER_THROTTLING_STATE s{};
375320
s.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
376321
s.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
377-
s.StateMask = 0; // favor performance (disable EcoQoS)
322+
s.StateMask = 0; // favor performance
378323
SetThreadInformation(GetCurrentThread(), ThreadPowerThrottling, &s, sizeof(s));
379324
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
380325
}
381326

327+
#else // =============================== LINUX =================================
328+
329+
#include <cstring>
330+
#include <iostream>
331+
#include <pthread.h>
332+
#include <sched.h>
333+
#include <sys/resource.h>
334+
#include <unistd.h>
335+
#include <vector>
336+
337+
struct GROUP_AFFINITY {}; // dummy placeholder for portability
338+
339+
// Simple round-robin CPU pinning on Linux
340+
static std::vector<int> pick_physical_cores(size_t N) {
341+
std::vector<int> cores;
342+
int ncpu = std::thread::hardware_concurrency();
343+
for (int i = 0; i < (int) N && i < ncpu; ++i)
344+
cores.push_back(i);
345+
return cores;
346+
}
347+
348+
inline void raise_process_priority() {
349+
if (setpriority(PRIO_PROCESS, 0, -10) != 0)
350+
std::cerr << "Warning: cannot raise process priority (" << strerror(errno) << ")\n";
351+
}
352+
353+
inline void configure_current_thread_for_performance() {
354+
pthread_t this_thread = pthread_self();
355+
cpu_set_t cpuset;
356+
CPU_ZERO(&cpuset);
357+
358+
static thread_local int next_core = 0;
359+
int ncpu = std::thread::hardware_concurrency();
360+
int core_id = next_core++ % ncpu;
361+
362+
CPU_SET(core_id, &cpuset);
363+
if (pthread_setaffinity_np(this_thread, sizeof(cpu_set_t), &cpuset) != 0)
364+
std::cerr << "Warning: cannot set CPU affinity (" << strerror(errno) << ")\n";
365+
366+
// Optional: try to lower nice value further
367+
setpriority(PRIO_PROCESS, 0, -10);
368+
}
369+
370+
#endif
371+
// ============================================================================
372+
373+
382374
// ===== End helpers =====
383375

384376
struct Config {
@@ -1826,15 +1818,18 @@ int main() {
18261818
eval_function_UR5e();
18271819
});
18281820

1829-
// Pin the thread immediately after creation
1821+
#ifdef _WIN32
1822+
// Only available on Windows — pin threads to P-cores
18301823
if (t < (int) cores.size()) {
18311824
SetThreadGroupAffinity(
18321825
(HANDLE) workers.back().native_handle(),
18331826
&cores[t],
18341827
nullptr);
18351828
}
1829+
#endif
18361830
}
18371831

1832+
18381833
for (auto& th: workers)
18391834
th.join();
18401835

‎examples/example_manipulator.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ int main() {
6666
auto t2 = get_tick_us();
6767
cout << "Compute time: " << (double) (t2 - t1) / 1000. << endl;
6868
cout << "Average compute time: " << (double) (t2 - t1) / 1000. / (real) max_iter << endl;
69-
cout << "Initial guess time: " << time_for_one_guess << endl;
69+
// cout << "Initial guess time: " << time_for_one_guess << endl;
7070

7171

7272
return 0;

‎tests/CMakeLists.txt‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ set(BENCHMARKS
3232
# bench_gradients_acceleration acceleration/bench_gradients_acceleration.cpp
3333
# bench_generic benchmarks/bench_generic.cpp
3434
# bench_test_manip benchmarks/bench_test_manip.cpp
35-
bench_manipulator benchmarks/bench_manipulator.cpp
36-
bench_accelerations acceleration/bench_accelerations.cpp
37-
bench_inplace acceleration/bench_inplace.cpp
38-
bench_paper_gradients benchmarks/bench_paper_gradients.cpp
35+
# bench_manipulator benchmarks/bench_manipulator.cpp
36+
# bench_accelerations acceleration/bench_accelerations.cpp
37+
# bench_inplace acceleration/bench_inplace.cpp
38+
# bench_paper_gradients benchmarks/bench_paper_gradients.cpp
3939
# bench_constraints benchmarks/bench_constraints.cpp
4040
# bench_functions benchmarks/bench_functions.cpp
4141
)
@@ -48,8 +48,8 @@ set(TESTS
4848
# Acceleration
4949
# test_gradients_acceleration acceleration/test_gradients_acceleration.cpp
5050
# test_constraints_acceleration acceleration/test_constraints_acceleration.cpp
51-
test_accelerations acceleration/test_accelerations.cpp
52-
test_inplace acceleration/test_inplace.cpp
51+
# test_accelerations acceleration/test_accelerations.cpp
52+
# test_inplace acceleration/test_inplace.cpp
5353

5454
# Container
5555
# test_container_objmatrix container/test_objmatrix.cpp

0 commit comments

Comments
 (0)