--- nono/vm/thread.cpp 2026/04/29 17:05:09 1.1.1.1 +++ nono/vm/thread.cpp 2026/04/29 17:05:28 1.1.1.3 @@ -9,11 +9,12 @@ // #include "thread.h" +#include "mainapp.h" #include "mythread.h" // コンストラクタ -ThreadDevice::ThreadDevice(const std::string& objname_) - : inherited(objname_) +ThreadDevice::ThreadDevice(uint objid_) + : inherited(objid_) { // スレッド名はデフォルトでこのオブジェクトと同じ名前にしておく。 // 継承側コンストラクタ等で SetThreadName() で変更してもよい。 @@ -71,3 +72,85 @@ ThreadDevice::TerminateThread() thread.reset(); } } + +// このスレッドアフィニティを設定する。 +void +ThreadDevice::SetThreadAffinityHint(AffinityClass hint) +{ +#if defined(HAVE_PTHREAD_SETAFFINITY_NP) && defined(HAVE_MICPUSET) + auto aff = gMainApp.cpu_affinity; + if (aff == MainApp::CPUAffinity::None) { + return; + } + + // hint, aff, cpu_list から cset を作成する。 + // + // aff hint list + // ----- ---- ---- + // Low Heavy 0 - + // Low Heavy 1 - + // High Light 0 - + // High Light 1 - + // ↑このケースは CPU を固定しないので cset の収集自体不要。 + // + // Low Light 0 - + // Low Light 1 set + // High Heavy 0 - + // High Heavy 1 set + // ↑このケースは list[] が true なところを固定。 + // + // Perf Light 0 set + // Perf Light 1 - + // Perf Heavy 0 - + // Perf Heavy 1 set + // ↑このケースは (bool)hint と list[] が一致したところを固定。 + + // このスレッドは CPU を固定しない。 + if ((hint == AffinityClass::Heavy && aff == MainApp::CPUAffinity::Low ) || + (hint == AffinityClass::Light && aff == MainApp::CPUAffinity::High)) + { + return; + } + + const std::vector& cpu_list = gMainApp.cpu_list; + MICPUSet cset; + for (int i = 0, end = cpu_list.size(); i < end; i++) { + if (aff == MainApp::CPUAffinity::Perf) { + // Light,Heavy と list が一致していたらセット。 + bool hintb = (hint == AffinityClass::Heavy); + if (hintb == cpu_list[i]) { + cset.Set(i); + } + } else { + // Low,High と Light,Heavy が一致しているので立ってるほうをセット。 + if (cpu_list[i]) { + cset.Set(i); + } + } + } + + int r = PTHREAD_SETAFFINITY(pthread_self(), cset); + + if (gMainApp.hostcpu->loglevel >= 1) { + std::string csetstr; + for (int i = 0, end = cpu_list.size(); i < end; i++) { + csetstr += '0' + (uint)cset.Get(i); + } + gMainApp.hostcpu->putmsgn("SetAffinity:%-12s(%s) %s%s%s", + PTHREAD_GETNAME().c_str(), + (hint == AffinityClass::Light ? "Light" : "Heavy"), + csetstr.c_str(), + (r == 0 ? "" : " = "), + (r == 0 ? "" : strerror(r))); + } + + // エラーなら errno ではなく戻り値にエラー番号が返ってくる。 + // NetBSD では sysctl で許可しないと一般ユーザはこの機能を使えないため + // EPERM で失敗したら以降はもう何もしない。 + if (r == EPERM) { + gMainApp.cpu_affinity = MainApp::CPUAffinity::None; + } +#else + // なければ無視する。 +#endif +}