diff options
Diffstat (limited to 'llvm/lib/Support/Windows')
-rw-r--r-- | llvm/lib/Support/Windows/DynamicLibrary.inc | 2 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Host.inc | 2 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Memory.inc | 2 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Path.inc | 117 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Process.inc | 48 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Program.inc | 30 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Signals.inc | 28 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/ThreadLocal.inc | 2 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Threading.inc | 176 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/WindowsSupport.h | 243 |
10 files changed, 328 insertions, 322 deletions
diff --git a/llvm/lib/Support/Windows/DynamicLibrary.inc b/llvm/lib/Support/Windows/DynamicLibrary.inc index 71b206c4cf9e..a3f78fb0d6ba 100644 --- a/llvm/lib/Support/Windows/DynamicLibrary.inc +++ b/llvm/lib/Support/Windows/DynamicLibrary.inc @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" diff --git a/llvm/lib/Support/Windows/Host.inc b/llvm/lib/Support/Windows/Host.inc index 21b947f26df3..5583db909045 100644 --- a/llvm/lib/Support/Windows/Host.inc +++ b/llvm/lib/Support/Windows/Host.inc @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include <cstdio> #include <string> diff --git a/llvm/lib/Support/Windows/Memory.inc b/llvm/lib/Support/Windows/Memory.inc index c5566f9910a5..1b2de1915ec4 100644 --- a/llvm/lib/Support/Windows/Memory.inc +++ b/llvm/lib/Support/Windows/Memory.inc @@ -17,7 +17,7 @@ #include "llvm/Support/WindowsError.h" // The Windows.h header must be the last one included. -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" static DWORD getWindowsProtectionFlags(unsigned Flags) { switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc index c3b13abef5de..e352beb77616 100644 --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -25,7 +25,7 @@ // These two headers must be included last, and make sure shlobj is required // after Windows.h to make sure it picks up our definition of _WIN32_WINNT -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include <shellapi.h> #include <shlobj.h> @@ -47,7 +47,7 @@ using namespace llvm; using llvm::sys::windows::UTF8ToUTF16; using llvm::sys::windows::CurCPToUTF16; using llvm::sys::windows::UTF16ToUTF8; -using llvm::sys::path::widenPath; +using llvm::sys::windows::widenPath; static bool is_separator(const wchar_t value) { switch (value) { @@ -61,64 +61,64 @@ static bool is_separator(const wchar_t value) { namespace llvm { namespace sys { -namespace path { +namespace windows { -// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the -// path is longer than CreateDirectory can tolerate, make it absolute and -// prefixed by '\\?\'. -std::error_code widenPath(const Twine &Path8, - SmallVectorImpl<wchar_t> &Path16) { - const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. +// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the path +// is longer than the limit that the Win32 Unicode File API can tolerate, make +// it an absolute normalized path prefixed by '\\?\'. +std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16, + size_t MaxPathLen) { + assert(MaxPathLen <= MAX_PATH); - // Several operations would convert Path8 to SmallString; more efficient to - // do it once up front. - SmallString<128> Path8Str; + // Several operations would convert Path8 to SmallString; more efficient to do + // it once up front. + SmallString<MAX_PATH> Path8Str; Path8.toVector(Path8Str); - // If we made this path absolute, how much longer would it get? + if (std::error_code EC = UTF8ToUTF16(Path8Str, Path16)) + return EC; + + const bool IsAbsolute = llvm::sys::path::is_absolute(Path8); size_t CurPathLen; - if (llvm::sys::path::is_absolute(Twine(Path8Str))) + if (IsAbsolute) CurPathLen = 0; // No contribution from current_path needed. else { - CurPathLen = ::GetCurrentDirectoryW(0, NULL); + CurPathLen = ::GetCurrentDirectoryW( + 0, NULL); // Returns the size including the null terminator. if (CurPathLen == 0) return mapWindowsError(::GetLastError()); } - // Would the absolute path be longer than our limit? - if ((Path8Str.size() + CurPathLen) >= MaxDirLen && - !Path8Str.startswith("\\\\?\\")) { - SmallString<2*MAX_PATH> FullPath("\\\\?\\"); - if (CurPathLen) { - SmallString<80> CurPath; - if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) - return EC; - FullPath.append(CurPath); - } - // Traverse the requested path, canonicalizing . and .. (because the \\?\ - // prefix is documented to treat them as real components). Ignore - // separators, which can be returned from the iterator if the path has a - // drive name. We don't need to call native() on the result since append() - // always attaches preferred_separator. - for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), - E = llvm::sys::path::end(Path8Str); - I != E; ++I) { - if (I->size() == 1 && is_separator((*I)[0])) - continue; - if (I->size() == 1 && *I == ".") - continue; - if (I->size() == 2 && *I == "..") - llvm::sys::path::remove_filename(FullPath); - else - llvm::sys::path::append(FullPath, *I); - } - return UTF8ToUTF16(FullPath, Path16); + const char *const LongPathPrefix = "\\\\?\\"; + + if ((Path16.size() + CurPathLen) < MaxPathLen || + Path8Str.startswith(LongPathPrefix)) + return std::error_code(); + + if (!IsAbsolute) { + if (std::error_code EC = llvm::sys::fs::make_absolute(Path8Str)) + return EC; } - // Just use the caller's original path. - return UTF8ToUTF16(Path8Str, Path16); + // Remove '.' and '..' because long paths treat these as real path components. + llvm::sys::path::native(Path8Str, path::Style::windows); + llvm::sys::path::remove_dots(Path8Str, true); + + const StringRef RootName = llvm::sys::path::root_name(Path8Str); + assert(!RootName.empty() && + "Root name cannot be empty for an absolute path!"); + + SmallString<2 * MAX_PATH> FullPath(LongPathPrefix); + if (RootName[1] != ':') { // Check if UNC. + FullPath.append("UNC\\"); + FullPath.append(Path8Str.begin() + 2, Path8Str.end()); + } else + FullPath.append(Path8Str); + + return UTF8ToUTF16(FullPath, Path16); } -} // end namespace path + +} // end namespace windows namespace fs { @@ -227,7 +227,9 @@ std::error_code create_directory(const Twine &path, bool IgnoreExisting, perms Perms) { SmallVector<wchar_t, 128> path_utf16; - if (std::error_code ec = widenPath(path, path_utf16)) + // CreateDirectoryW has a lower maximum path length as it must leave room for + // an 8.3 filename. + if (std::error_code ec = widenPath(path, path_utf16, MAX_PATH - 12)) return ec; if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { @@ -553,6 +555,11 @@ std::error_code rename(const Twine &From, const Twine &To) { NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (FromHandle) break; + + // We don't want to loop if the file doesn't exist. + auto EC = mapWindowsError(GetLastError()); + if (EC == errc::no_such_file_or_directory) + return EC; } if (!FromHandle) return mapWindowsError(GetLastError()); @@ -950,9 +957,9 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &IT, return EC; // Convert path to the format that Windows is happy with. - if (PathUTF16.size() > 0 && - !is_separator(PathUTF16[Path.size() - 1]) && - PathUTF16[Path.size() - 1] != L':') { + size_t PathUTF16Len = PathUTF16.size(); + if (PathUTF16Len > 0 && !is_separator(PathUTF16[PathUTF16Len - 1]) && + PathUTF16[PathUTF16Len - 1] != L':') { PathUTF16.push_back(L'\\'); PathUTF16.push_back(L'*'); } else { @@ -1365,6 +1372,16 @@ bool home_directory(SmallVectorImpl<char> &result) { return getKnownFolderPath(FOLDERID_Profile, result); } +bool user_config_directory(SmallVectorImpl<char> &result) { + // Either local or roaming appdata may be suitable in some cases, depending + // on the data. Local is more conservative, Roaming may not always be correct. + return getKnownFolderPath(FOLDERID_LocalAppData, result); +} + +bool cache_directory(SmallVectorImpl<char> &result) { + return getKnownFolderPath(FOLDERID_LocalAppData, result); +} + static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl<char> &Res) { SmallVector<wchar_t, 1024> Buf; size_t Size = 1024; diff --git a/llvm/lib/Support/Windows/Process.inc b/llvm/lib/Support/Windows/Process.inc index 3526e3dee6fa..8064d4e17b29 100644 --- a/llvm/lib/Support/Windows/Process.inc +++ b/llvm/lib/Support/Windows/Process.inc @@ -19,7 +19,7 @@ #include <malloc.h> // The Windows.h header must be after LLVM and standard headers. -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include <direct.h> #include <io.h> @@ -43,6 +43,12 @@ using namespace llvm; +Process::Pid Process::getProcessId() { + static_assert(sizeof(Pid) >= sizeof(DWORD), + "Process::Pid should be big enough to store DWORD"); + return Pid(::GetCurrentProcessId()); +} + // This function retrieves the page size using GetNativeSystemInfo() and is // present solely so it can be called once to initialize the self_process member // below. @@ -439,18 +445,38 @@ const char *Process::ResetColor() { return 0; } +static unsigned GetRandomNumberSeed() { + // Generate a random number seed from the millisecond-resolution Windows + // system clock and the current process id. + FILETIME Time; + GetSystemTimeAsFileTime(&Time); + DWORD Pid = GetCurrentProcessId(); + return hash_combine(Time.dwHighDateTime, Time.dwLowDateTime, Pid); +} + +static unsigned GetPseudoRandomNumber() { + // Arrange to call srand once when this function is first used, and + // otherwise (if GetRandomNumber always succeeds in using + // CryptGenRandom) don't bother at all. + static int x = (static_cast<void>(::srand(GetRandomNumberSeed())), 0); + (void)x; + return ::rand(); +} + unsigned Process::GetRandomNumber() { + // Try to use CryptGenRandom. HCRYPTPROV HCPC; - if (!::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) - ReportLastErrorFatal("Could not acquire a cryptographic context"); - - ScopedCryptContext CryptoProvider(HCPC); - unsigned Ret; - if (!::CryptGenRandom(CryptoProvider, sizeof(Ret), - reinterpret_cast<BYTE *>(&Ret))) - ReportLastErrorFatal("Could not generate a random number"); - return Ret; + if (::CryptAcquireContextW(&HCPC, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) { + ScopedCryptContext CryptoProvider(HCPC); + unsigned Ret; + if (::CryptGenRandom(CryptoProvider, sizeof(Ret), + reinterpret_cast<BYTE *>(&Ret))) + return Ret; + } + + // If that fails, fall back to pseudo-random numbers. + return GetPseudoRandomNumber(); } typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); diff --git a/llvm/lib/Support/Windows/Program.inc b/llvm/lib/Support/Windows/Program.inc index a1482bf17c60..9fe05d24ec2e 100644 --- a/llvm/lib/Support/Windows/Program.inc +++ b/llvm/lib/Support/Windows/Program.inc @@ -10,14 +10,15 @@ // //===----------------------------------------------------------------------===// -#include "WindowsSupport.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include "llvm/Support/WindowsError.h" #include "llvm/Support/raw_ostream.h" +#include <psapi.h> #include <cstdio> #include <fcntl.h> #include <io.h> @@ -138,7 +139,7 @@ static HANDLE RedirectIO(Optional<StringRef> Path, int fd, if (Path->empty()) fname = "NUL"; else - fname = *Path; + fname = std::string(*Path); SECURITY_ATTRIBUTES sa; sa.nLength = sizeof(sa); @@ -151,7 +152,7 @@ static HANDLE RedirectIO(Optional<StringRef> Path, int fd, if (windows::UTF8ToUTF16(fname, fnameUnicode)) return INVALID_HANDLE_VALUE; } else { - if (path::widenPath(fname, fnameUnicode)) + if (sys::windows::widenPath(fname, fnameUnicode)) return INVALID_HANDLE_VALUE; } h = CreateFileW(fnameUnicode.data(), fd ? GENERIC_WRITE : GENERIC_READ, @@ -263,7 +264,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, fflush(stderr); SmallVector<wchar_t, MAX_PATH> ProgramUtf16; - if (std::error_code ec = path::widenPath(Program, ProgramUtf16)) { + if (std::error_code ec = sys::windows::widenPath(Program, ProgramUtf16)) { SetLastError(ec.value()); MakeErrMsg(ErrMsg, std::string("Unable to convert application name to UTF-16")); @@ -390,7 +391,8 @@ std::string sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) { } ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, - bool WaitUntilChildTerminates, std::string *ErrMsg) { + bool WaitUntilChildTerminates, std::string *ErrMsg, + Optional<ProcessStatistics> *ProcStat) { assert(PI.Pid && "invalid pid to wait on, process not started?"); assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) && "invalid process handle to wait on, process not started?"); @@ -401,6 +403,8 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, milliSecondsToWait = SecondsToWait * 1000; ProcessInfo WaitResult = PI; + if (ProcStat) + ProcStat->reset(); DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait); if (WaitStatus == WAIT_TIMEOUT) { if (SecondsToWait) { @@ -421,6 +425,22 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, } } + // Get process execution statistics. + if (ProcStat) { + FILETIME CreationTime, ExitTime, KernelTime, UserTime; + PROCESS_MEMORY_COUNTERS MemInfo; + if (GetProcessTimes(PI.Process, &CreationTime, &ExitTime, &KernelTime, + &UserTime) && + GetProcessMemoryInfo(PI.Process, &MemInfo, sizeof(MemInfo))) { + auto UserT = std::chrono::duration_cast<std::chrono::microseconds>( + toDuration(UserTime)); + auto KernelT = std::chrono::duration_cast<std::chrono::microseconds>( + toDuration(KernelTime)); + uint64_t PeakMemory = MemInfo.PeakPagefileUsage / 1024; + *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory}; + } + } + // Get its exit status. DWORD status; BOOL rc = GetExitCodeProcess(PI.Process, &status); diff --git a/llvm/lib/Support/Windows/Signals.inc b/llvm/lib/Support/Windows/Signals.inc index 8b525f1bd4ac..0c3681fa9654 100644 --- a/llvm/lib/Support/Windows/Signals.inc +++ b/llvm/lib/Support/Windows/Signals.inc @@ -23,7 +23,7 @@ #include "llvm/Support/raw_ostream.h" // The Windows.h header must be after LLVM and standard headers. -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #ifdef __MINGW32__ #include <imagehlp.h> @@ -460,7 +460,7 @@ bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { if (FilesToRemove == NULL) FilesToRemove = new std::vector<std::string>; - FilesToRemove->push_back(Filename); + FilesToRemove->push_back(std::string(Filename)); LeaveCriticalSection(&CriticalSection); return false; @@ -584,7 +584,7 @@ void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, LeaveCriticalSection(&CriticalSection); } -static void Cleanup() { +static void Cleanup(bool ExecuteSignalHandlers) { if (CleanupExecuted) return; @@ -600,7 +600,10 @@ static void Cleanup() { llvm::sys::fs::remove(FilesToRemove->back()); FilesToRemove->pop_back(); } - llvm::sys::RunSignalHandlers(); + + if (ExecuteSignalHandlers) + llvm::sys::RunSignalHandlers(); + LeaveCriticalSection(&CriticalSection); } @@ -610,7 +613,7 @@ void llvm::sys::RunInterruptHandlers() { // error handler). We must ensure that the critical section is properly // initialized. InitializeThreading(); - Cleanup(); + Cleanup(true); } /// Find the Windows Registry Key for a given location. @@ -803,7 +806,7 @@ void sys::CleanupOnSignal(uintptr_t Context) { } static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { - Cleanup(); + Cleanup(true); // We'll automatically write a Minidump file here to help diagnose // the nasty sorts of crashes that aren't 100% reproducible from a set of @@ -820,7 +823,13 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { << "\n"; } - LocalPrintStackTrace(llvm::errs(), ep ? ep->ContextRecord : nullptr); + // Stack unwinding appears to modify the context. Copy it to preserve the + // caller's context. + CONTEXT ContextCopy; + if (ep) + memcpy(&ContextCopy, ep->ContextRecord, sizeof(ContextCopy)); + + LocalPrintStackTrace(llvm::errs(), ep ? &ContextCopy : nullptr); return EXCEPTION_EXECUTE_HANDLER; } @@ -828,7 +837,10 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { // We are running in our very own thread, courtesy of Windows. EnterCriticalSection(&CriticalSection); - Cleanup(); + // This function is only ever called when a CTRL-C or similar control signal + // is fired. Killing a process in this way is normal, so don't trigger the + // signal handlers. + Cleanup(false); // If an interrupt function has been set, go and run one it; otherwise, // the process dies. diff --git a/llvm/lib/Support/Windows/ThreadLocal.inc b/llvm/lib/Support/Windows/ThreadLocal.inc index 1e0ed955e9ab..696e5c843ead 100644 --- a/llvm/lib/Support/Windows/ThreadLocal.inc +++ b/llvm/lib/Support/Windows/ThreadLocal.inc @@ -15,7 +15,7 @@ //=== is guaranteed to work on *all* Win32 variants. //===----------------------------------------------------------------------===// -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include "llvm/Support/ThreadLocal.h" namespace llvm { diff --git a/llvm/lib/Support/Windows/Threading.inc b/llvm/lib/Support/Windows/Threading.inc index 9456efa686ff..296e87b77695 100644 --- a/llvm/lib/Support/Windows/Threading.inc +++ b/llvm/lib/Support/Windows/Threading.inc @@ -13,9 +13,11 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" -#include "WindowsSupport.h" +#include "llvm/Support/Windows/WindowsSupport.h" #include <process.h> +#include <bitset> + // Windows will at times define MemoryFence. #ifdef MemoryFence #undef MemoryFence @@ -122,3 +124,175 @@ SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { ? SetThreadPriorityResult::SUCCESS : SetThreadPriorityResult::FAILURE; } + +struct ProcessorGroup { + unsigned ID; + unsigned AllThreads; + unsigned UsableThreads; + unsigned ThreadsPerCore; + uint64_t Affinity; + + unsigned useableCores() const { + return std::max(1U, UsableThreads / ThreadsPerCore); + } +}; + +template <typename F> +static bool IterateProcInfo(LOGICAL_PROCESSOR_RELATIONSHIP Relationship, F Fn) { + DWORD Len = 0; + BOOL R = ::GetLogicalProcessorInformationEx(Relationship, NULL, &Len); + if (R || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + return false; + } + auto *Info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)calloc(1, Len); + R = ::GetLogicalProcessorInformationEx(Relationship, Info, &Len); + if (R) { + auto *End = + (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Info + Len); + for (auto *Curr = Info; Curr < End; + Curr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Curr + + Curr->Size)) { + if (Curr->Relationship != Relationship) + continue; + Fn(Curr); + } + } + free(Info); + return true; +} + +static ArrayRef<ProcessorGroup> getProcessorGroups() { + auto computeGroups = []() { + SmallVector<ProcessorGroup, 4> Groups; + + auto HandleGroup = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) { + GROUP_RELATIONSHIP &El = ProcInfo->Group; + for (unsigned J = 0; J < El.ActiveGroupCount; ++J) { + ProcessorGroup G; + G.ID = Groups.size(); + G.AllThreads = El.GroupInfo[J].MaximumProcessorCount; + G.UsableThreads = El.GroupInfo[J].ActiveProcessorCount; + assert(G.UsableThreads <= 64); + G.Affinity = El.GroupInfo[J].ActiveProcessorMask; + Groups.push_back(G); + } + }; + + if (!IterateProcInfo(RelationGroup, HandleGroup)) + return std::vector<ProcessorGroup>(); + + auto HandleProc = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) { + PROCESSOR_RELATIONSHIP &El = ProcInfo->Processor; + assert(El.GroupCount == 1); + unsigned NumHyperThreads = 1; + // If the flag is set, each core supports more than one hyper-thread. + if (El.Flags & LTP_PC_SMT) + NumHyperThreads = std::bitset<64>(El.GroupMask[0].Mask).count(); + unsigned I = El.GroupMask[0].Group; + Groups[I].ThreadsPerCore = NumHyperThreads; + }; + + if (!IterateProcInfo(RelationProcessorCore, HandleProc)) + return std::vector<ProcessorGroup>(); + + // If there's an affinity mask set on one of the CPUs, then assume the user + // wants to constrain the current process to only a single CPU. + for (auto &G : Groups) { + if (G.UsableThreads != G.AllThreads) { + ProcessorGroup NewG{G}; + Groups.clear(); + Groups.push_back(NewG); + break; + } + } + + return std::vector<ProcessorGroup>(Groups.begin(), Groups.end()); + }; + static auto Groups = computeGroups(); + return ArrayRef<ProcessorGroup>(Groups); +} + +template <typename R, typename UnaryPredicate> +static unsigned aggregate(R &&Range, UnaryPredicate P) { + unsigned I{}; + for (const auto &It : Range) + I += P(It); + return I; +} + +// for sys::getHostNumPhysicalCores +int computeHostNumPhysicalCores() { + static unsigned Cores = + aggregate(getProcessorGroups(), [](const ProcessorGroup &G) { + return G.UsableThreads / G.ThreadsPerCore; + }); + return Cores; +} + +int computeHostNumHardwareThreads() { + static unsigned Threads = + aggregate(getProcessorGroups(), + [](const ProcessorGroup &G) { return G.UsableThreads; }); + return Threads; +} + +// Finds the proper CPU socket where a thread number should go. Returns 'None' +// if the thread shall remain on the actual CPU socket. +Optional<unsigned> +llvm::ThreadPoolStrategy::compute_cpu_socket(unsigned ThreadPoolNum) const { + ArrayRef<ProcessorGroup> Groups = getProcessorGroups(); + // Only one CPU socket in the system or process affinity was set, no need to + // move the thread(s) to another CPU socket. + if (Groups.size() <= 1) + return None; + + // We ask for less threads than there are hardware threads per CPU socket, no + // need to dispatch threads to other CPU sockets. + unsigned MaxThreadsPerSocket = + UseHyperThreads ? Groups[0].UsableThreads : Groups[0].useableCores(); + if (compute_thread_count() <= MaxThreadsPerSocket) + return None; + + assert(ThreadPoolNum < compute_thread_count() && + "The thread index is not within thread strategy's range!"); + + // Assumes the same number of hardware threads per CPU socket. + return (ThreadPoolNum * Groups.size()) / compute_thread_count(); +} + +// Assign the current thread to a more appropriate CPU socket or CPU group +void llvm::ThreadPoolStrategy::apply_thread_strategy( + unsigned ThreadPoolNum) const { + Optional<unsigned> Socket = compute_cpu_socket(ThreadPoolNum); + if (!Socket) + return; + ArrayRef<ProcessorGroup> Groups = getProcessorGroups(); + GROUP_AFFINITY Affinity{}; + Affinity.Group = Groups[*Socket].ID; + Affinity.Mask = Groups[*Socket].Affinity; + SetThreadGroupAffinity(GetCurrentThread(), &Affinity, nullptr); +} + +llvm::BitVector llvm::get_thread_affinity_mask() { + GROUP_AFFINITY Affinity{}; + GetThreadGroupAffinity(GetCurrentThread(), &Affinity); + + static unsigned All = + aggregate(getProcessorGroups(), + [](const ProcessorGroup &G) { return G.AllThreads; }); + + unsigned StartOffset = + aggregate(getProcessorGroups(), [&](const ProcessorGroup &G) { + return G.ID < Affinity.Group ? G.AllThreads : 0; + }); + + llvm::BitVector V; + V.resize(All); + for (unsigned I = 0; I < sizeof(KAFFINITY) * 8; ++I) { + if ((Affinity.Mask >> I) & 1) + V.set(StartOffset + I); + } + return V; +} + +unsigned llvm::get_cpus() { return getProcessorGroups().size(); } diff --git a/llvm/lib/Support/Windows/WindowsSupport.h b/llvm/lib/Support/Windows/WindowsSupport.h deleted file mode 100644 index bb7e79b86018..000000000000 --- a/llvm/lib/Support/Windows/WindowsSupport.h +++ /dev/null @@ -1,243 +0,0 @@ -//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines things specific to Windows implementations. In addition to -// providing some helpers for working with win32 APIs, this header wraps -// <windows.h> with some portability macros. Always include WindowsSupport.h -// instead of including <windows.h> directly. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H -#define LLVM_SUPPORT_WINDOWSSUPPORT_H - -// mingw-w64 tends to define it as 0x0502 in its headers. -#undef _WIN32_WINNT -#undef _WIN32_IE - -// Require at least Windows 7 API. -#define _WIN32_WINNT 0x0601 -#define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed. -#define WIN32_LEAN_AND_MEAN -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Config/config.h" // Get build system configuration settings -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Chrono.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/VersionTuple.h" -#include <cassert> -#include <string> -#include <system_error> -#include <windows.h> - -// Must be included after windows.h -#include <wincrypt.h> - -namespace llvm { - -/// Determines if the program is running on Windows 8 or newer. This -/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended -/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't -/// yet have VersionHelpers.h, so we have our own helper. -bool RunningWindows8OrGreater(); - -/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses -/// RtlGetVersion or GetVersionEx under the hood depending on what is available. -/// GetVersionEx is deprecated, but this API exposes the build number which can -/// be useful for working around certain kernel bugs. -llvm::VersionTuple GetWindowsOSVersion(); - -bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix); - -// Include GetLastError() in a fatal error message. -LLVM_ATTRIBUTE_NORETURN inline void ReportLastErrorFatal(const char *Msg) { - std::string ErrMsg; - MakeErrMsg(&ErrMsg, Msg); - llvm::report_fatal_error(ErrMsg); -} - -template <typename HandleTraits> -class ScopedHandle { - typedef typename HandleTraits::handle_type handle_type; - handle_type Handle; - - ScopedHandle(const ScopedHandle &other) = delete; - void operator=(const ScopedHandle &other) = delete; -public: - ScopedHandle() - : Handle(HandleTraits::GetInvalid()) {} - - explicit ScopedHandle(handle_type h) - : Handle(h) {} - - ~ScopedHandle() { - if (HandleTraits::IsValid(Handle)) - HandleTraits::Close(Handle); - } - - handle_type take() { - handle_type t = Handle; - Handle = HandleTraits::GetInvalid(); - return t; - } - - ScopedHandle &operator=(handle_type h) { - if (HandleTraits::IsValid(Handle)) - HandleTraits::Close(Handle); - Handle = h; - return *this; - } - - // True if Handle is valid. - explicit operator bool() const { - return HandleTraits::IsValid(Handle) ? true : false; - } - - operator handle_type() const { - return Handle; - } -}; - -struct CommonHandleTraits { - typedef HANDLE handle_type; - - static handle_type GetInvalid() { - return INVALID_HANDLE_VALUE; - } - - static void Close(handle_type h) { - ::CloseHandle(h); - } - - static bool IsValid(handle_type h) { - return h != GetInvalid(); - } -}; - -struct JobHandleTraits : CommonHandleTraits { - static handle_type GetInvalid() { - return NULL; - } -}; - -struct CryptContextTraits : CommonHandleTraits { - typedef HCRYPTPROV handle_type; - - static handle_type GetInvalid() { - return 0; - } - - static void Close(handle_type h) { - ::CryptReleaseContext(h, 0); - } - - static bool IsValid(handle_type h) { - return h != GetInvalid(); - } -}; - -struct RegTraits : CommonHandleTraits { - typedef HKEY handle_type; - - static handle_type GetInvalid() { - return NULL; - } - - static void Close(handle_type h) { - ::RegCloseKey(h); - } - - static bool IsValid(handle_type h) { - return h != GetInvalid(); - } -}; - -struct FindHandleTraits : CommonHandleTraits { - static void Close(handle_type h) { - ::FindClose(h); - } -}; - -struct FileHandleTraits : CommonHandleTraits {}; - -typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle; -typedef ScopedHandle<FileHandleTraits> ScopedFileHandle; -typedef ScopedHandle<CryptContextTraits> ScopedCryptContext; -typedef ScopedHandle<RegTraits> ScopedRegHandle; -typedef ScopedHandle<FindHandleTraits> ScopedFindHandle; -typedef ScopedHandle<JobHandleTraits> ScopedJobHandle; - -template <class T> -class SmallVectorImpl; - -template <class T> -typename SmallVectorImpl<T>::const_pointer -c_str(SmallVectorImpl<T> &str) { - str.push_back(0); - str.pop_back(); - return str.data(); -} - -namespace sys { - -inline std::chrono::nanoseconds toDuration(FILETIME Time) { - ULARGE_INTEGER TimeInteger; - TimeInteger.LowPart = Time.dwLowDateTime; - TimeInteger.HighPart = Time.dwHighDateTime; - - // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) - return std::chrono::nanoseconds(100 * TimeInteger.QuadPart); -} - -inline TimePoint<> toTimePoint(FILETIME Time) { - ULARGE_INTEGER TimeInteger; - TimeInteger.LowPart = Time.dwLowDateTime; - TimeInteger.HighPart = Time.dwHighDateTime; - - // Adjust for different epoch - TimeInteger.QuadPart -= 11644473600ll * 10000000; - - // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) - return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart)); -} - -inline FILETIME toFILETIME(TimePoint<> TP) { - ULARGE_INTEGER TimeInteger; - TimeInteger.QuadPart = TP.time_since_epoch().count() / 100; - TimeInteger.QuadPart += 11644473600ll * 10000000; - - FILETIME Time; - Time.dwLowDateTime = TimeInteger.LowPart; - Time.dwHighDateTime = TimeInteger.HighPart; - return Time; -} - -namespace windows { -// Returns command line arguments. Unlike arguments given to main(), -// this function guarantees that the returned arguments are encoded in -// UTF-8 regardless of the current code page setting. -std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args, - BumpPtrAllocator &Alloc); -} // end namespace windows -} // end namespace sys -} // end namespace llvm. - -#endif |